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.

2689 lines
83 KiB

  1. PAGE ,132
  2. TITLE DXMMGR - Dos Extender Memory Management Routines
  3. ; Copyright (c) Microsoft Corporation 1988-1991. All Rights Reserved.
  4. ;****************************************************************
  5. ;* *
  6. ;* DXMMGR.ASM - Dos Extender Memory Manager *
  7. ;* *
  8. ;****************************************************************
  9. ;* *
  10. ;* Module Description: *
  11. ;* *
  12. ;* This module contains routines for maintaining a dynamic *
  13. ;* memory heap in extended memory for use in the Dos Extender. *
  14. ;* *
  15. ;* There are two kinds of objects in the memory heap. There *
  16. ;* are block headers and data blocks. The block headers are *
  17. ;* each 16 bytes long, and are organized in a doubly linked *
  18. ;* list. There is a segment descriptor in the global *
  19. ;* descriptor table for each block header, with each header *
  20. ;* containing the selectors for the next and previous block *
  21. ;* to form the list. Block headers can either control a free *
  22. ;* block or they can control a data block. In either case, *
  23. ;* the block immediately follows the header in memory, and *
  24. ;* the header contains a field that gives its size. Free *
  25. ;* blocks do not have a descriptor in the global descriptor *
  26. ;* table, but in use data blocks do. In the case where the *
  27. ;* in use data block is larger than 64k, there will be a *
  28. ;* contiguous range of selectors for the block. The block *
  29. ;* header contains a field giving the initial selector for *
  30. ;* the data block for in use blocks. *
  31. ;* *
  32. ;* A special type of free block serve as sentinels. They mark *
  33. ;* start and end of each physical block of memory available to *
  34. ;* the memory manager. They are identified by the reserved *
  35. ;* value of 0FFFE (start sentinel) and 0FFFF (end sentinel) in *
  36. ;* the selBlkOwner field. Unlike other blocks, they may not be *
  37. ;* moved without appeal to some higher level of memory *
  38. ;* allocation. *
  39. ;* *
  40. ;* Except for a pair of sentinels, a pair of blocks are *
  41. ;* contiguous in memory if and only if their headers are *
  42. ;* adjacent in the header chain. *
  43. ;* *
  44. ;* The blocks at the start and end of the header chain are *
  45. ;* sentinals. Their selectors are stored in global variables. *
  46. ;* The start and end of the block header chain are identified *
  47. ;* by NULL (0) pointers in the Next and Previous pointer fields*
  48. ;* respectively. *
  49. ;* *
  50. ;****************************************************************
  51. ;* Naming Conventions Used: *
  52. ;* *
  53. ;* The following hungarian prefixes are used in this module: *
  54. ;* lp - far pointer (selector:offset) *
  55. ;* bp - linear byte pointer (32 bit byte offset from *
  56. ;* the beginning of memory) *
  57. ;* p - near pointer (16 bit offset) *
  58. ;* sel - protected mode segment selector *
  59. ;* seg - real mode paragraph address *
  60. ;* cb - count of bytes *
  61. ;* id - generic byte that contains an ID code *
  62. ;* hmem - handle to XMS extended memory block *
  63. ;* *
  64. ;****************************************************************
  65. ;* Revision History: *
  66. ;* *
  67. ;* 11/28/90 amitc IntLowHeap allocates memory from Switcher *
  68. ;* if it can. *
  69. ;* *
  70. ;* 08/08/90 earleh DOSX and client privilege ring determined *
  71. ;* by equate in pmdefs.inc *
  72. ;* 05/09/90 jimmat Started VCPI changes. *
  73. ;* 05/09/90 jimmat Incorporated bug fix from CodeView folks, *
  74. ;* changes marked with [01] *
  75. ;* 06/23/89 jimmat: Added init of variable with heap handle *
  76. ;* 04/17/89 jimmat: Added routines for special low memory *
  77. ;* heap for use by network mapping *
  78. ;* 03/28/89 jimmat: Incorporated bug fixes from GeneA *
  79. ;* 02/10/89 (GeneA): changed Dos Extender from small model to *
  80. ;* medium model *
  81. ;* 12/07/88 (GeneA): moved SetupHimemDriver to dxinit.asm *
  82. ;* 08/30/88 (GeneA): created *
  83. ;* *
  84. ;****************************************************************
  85. .286p
  86. ; -------------------------------------------------------
  87. ; INCLUDE FILE DEFINITIONS
  88. ; -------------------------------------------------------
  89. include gendefs.inc
  90. include segdefs.inc
  91. include pmdefs.inc
  92. include dpmi.inc
  93. ; -------------------------------------------------------
  94. ; GENERAL SYMBOL DEFINITIONS
  95. ; -------------------------------------------------------
  96. ; -------------------------------------------------------
  97. ; EXTERNAL SYMBOL DEFINITIONS
  98. ; -------------------------------------------------------
  99. extrn XMScontrol:FAR
  100. pmxmssvc macro fcn
  101. ifnb <fcn>
  102. mov ah, fcn
  103. endif
  104. call XMScontrol
  105. endm
  106. extrn FreeSelector:NEAR
  107. extrn FreeSelectorBlock:NEAR
  108. extrn AllocateSelector:NEAR
  109. extrn AllocateSelectorBlock:NEAR
  110. extrn GetSegmentAddress:NEAR
  111. extrn SetSegmentAddress:NEAR
  112. extrn DupSegmentDscr:NEAR
  113. externFP NSetSegmentDscr
  114. extrn RemoveFreeDescriptor:NEAR
  115. extrn EnterProtectedMode:NEAR
  116. extrn EnterRealMode:NEAR
  117. extrn MoveMemBlock:NEAR
  118. ifdef WOW_x86
  119. externNP NSetSegmentAccess
  120. externNP NSetSegmentBase
  121. externNP NSetSegmentLimit
  122. endif
  123. DXDATA segment
  124. extrn selPSPChild:WORD
  125. extrn selGDT:WORD
  126. extrn bpGDT:FWORD
  127. ifdef WOW_x86
  128. extrn FastBop:fword
  129. endif
  130. DXDATA ends
  131. ; -------------------------------------------------------
  132. ; DATA SEGMENT DECLARATIONS
  133. ; -------------------------------------------------------
  134. DXDATA segment
  135. ; Minimum xmem allocation in K
  136. ; Note: This value MUST be a power of 2!!!
  137. ; Note: We will allocate a smaller block if only smaller blocks
  138. ; are available from xms
  139. XMEM_MIN_ALLOC equ 256
  140. extrn lpfnXmsFunc:DWORD
  141. ;
  142. ; These variables control access to the extended memory heap.
  143. public cKbInitialHeapSize
  144. cKbInitialHeapSize dw -1 ; Optional specification for first block
  145. ; of extended memory in KB.
  146. public dsegCurrent
  147. dsegCurrent dw 0 ; Paragraph count if the current block comes from DOS
  148. public hmemHeap
  149. hmemHeap dw ? ;XMS memory manager handle to the memory
  150. ; block containing the heap
  151. bpHeapStart dd ? ;byte address of start of heap
  152. ; (points to block header of first heap block)
  153. bpHeapEnd dd ? ;byte address of end of heap
  154. ; (points to block header of last heap block)
  155. cbHeapMove dd ? ;number of bytes by which a subheap moved
  156. public cbHeapSize,selLowHeapStart,selHiHeapStart,selHeapStart
  157. cbHeapSize dd ? ;number of bytes in the heap
  158. selHeapStart dw ? ;selector for the sentinel block at the
  159. ; start of the heap list
  160. bpCurTop dd 0 ;current top of compacted heap
  161. ; (used during heap compaction)
  162. cbHeapBlkMax dd ? ;size of largest free block seen while
  163. ; searching the heap
  164. cbHeapFreeSpace dd ? ;total free space in the heap
  165. selHiHeapStart dw ? ;selector for the sentinel block at the start
  166. ; of the higm memory heap
  167. selLowHeapStart dw ? ;selector for the sentinel block at the start
  168. ; of the special low heap
  169. segLowHeap dw ? ;segment address of low memory heap
  170. selLowHeapEnd dw ? ;selector for the sentinel block at the end
  171. ; of the special low heap
  172. fDosErr db ?
  173. public hmem_XMS_Table,hmem_XMS_Count
  174. hmem_XMS_Table dw CXMSBLOCKSDX DUP(0)
  175. hmem_XMS_Count dw 0
  176. public NoAsyncSwitching
  177. NoAsyncSwitching db 0 ;0=> async switching allowed
  178. public LowMemAllocFn,LowMemFreeFn
  179. LowMemAllocFn dd 0
  180. LowMemFreeFn dd 0
  181. DXDATA ends
  182. ; -------------------------------------------------------
  183. ; MISCELLANEOUS DATA STRUCTURE DECLARATIONS
  184. ; -------------------------------------------------------
  185. ; ****** also in dxvcpi.asm ******
  186. .ERRE CB_MEMHDR EQ 10h ;size of memory block header
  187. ; ****** also in dxvcpi.asm ******
  188. ; This segment declaration describes the format of the memory
  189. ; block header at the beginning of each object in the heap.
  190. MEMHDR segment at 0 ;Analogous to MS-DOS arenas
  191. fBlkStatus db ? ;Status bits about the arena block
  192. cselBlkData db ? ;number of selectors used by the data block
  193. ; that this arena header controls
  194. selBlkData dw ? ;initial selector for the data block that this
  195. ; arena header controls.
  196. ; (if the block is >64k, this is the first of the
  197. ; range of selectors assigned to the block)
  198. selBlkOwner dw ? ;PSP selector of owner. 0 if free.
  199. ;
  200. ; !!!!! There is code in ModifyXmemBlock which depends on the previous
  201. ; !!!!! four fields (and only those) being at lower addresses than selBlkHdr.
  202. ;
  203. selBlkHdr dw ? ;the selector of the block header. This points
  204. ; back at itself, so that we can find the selector
  205. ; to the header from its address
  206. selBlkNext dw ? ; next block header selector
  207. selBlkPrev dw ? ; previous block header selector
  208. cbBlkLen LABEL DWORD ; Block size in bytes
  209. hBlockHandle dw ? ; The handle returned by DOS or HIMEM
  210. dsegBlock dw ? ; 0 => HIMEM ELSE DOS paragraph count
  211. MEMHDR ends
  212. ; -------------------------------------------------------
  213. subttl Initialization Routines
  214. page
  215. DXPMCODE segment
  216. assume cs:DXPMCODE
  217. ; -------------------------------------------------------
  218. ; INITIALIZATION ROUTINES
  219. ; -------------------------------------------------------
  220. ;
  221. ; InitLowHeap -- Allocate and initialize the special low
  222. ; memory heap for use by network buffers
  223. ; and the like.
  224. ;
  225. ; Input: AX - number of K bytes of LOW heap needed
  226. ; (assumed to be < 1 Meg)
  227. ; Output: none
  228. ; Errors: CY set if error occurs
  229. ; Uses: All registers preserved
  230. ;
  231. ; Note: This routine must be called in protected mode
  232. ; and it assumes that interrupts should be enabled
  233. ; while it runs.
  234. assume ds:DGROUP,es:DGROUP,ss:NOTHING
  235. public InitLowHeap
  236. InitLowHeap proc near
  237. ret
  238. InitLowHeap endp
  239. ; -------------------------------------------------------
  240. ; AddToXmemHeap -- This routine will add a block of memory
  241. ; to the extended memory heap. It creates the sentinel header
  242. ; blocks and a header block for a free object containing
  243. ; the new memory.
  244. ;
  245. ; Input: CX - Least significant part of minimum block length required
  246. ; DX - Most significant part of minimum block length required
  247. ; Output: None
  248. ; Errors: None
  249. ; Uses:
  250. ; NOTES: This routine must be called in protected mode.
  251. ; With XMS-only providing memory, all XMS memory is allocated
  252. ; the first time this routine is called.
  253. ;
  254. ; If VCPI is active, and VCPI memory is being used, then
  255. ; enough memory is allocated from the server to satisfy
  256. ; the request. The allocation is handled in dxvcpi.asm.
  257. ;
  258. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  259. cProc AddToXmemHeap,<NEAR,PUBLIC>,<ax,bx,cx,dx,si,es>
  260. cBegin
  261. ;
  262. ; Add to requested size the size of our header overhead
  263. ;
  264. add cx,3*CB_MEMHDR ; Adjust for header overhead
  265. adc dx,0
  266. ;
  267. ; Round allocation up to next MIN_ALLOC size by first rounding up to the
  268. ; nearest 1K, then converting to K and rounding
  269. ;
  270. add cx,1023
  271. adc dx,0
  272. shr cx,10
  273. push dx
  274. shl dx,6
  275. or cx,dx ; cx is now size rounded to K
  276. pop dx
  277. add cx,XMEM_MIN_ALLOC - 1
  278. adc dx,0
  279. and cx,NOT (XMEM_MIN_ALLOC - 1) ; rounded to next higher MIN_ALLOC
  280. ; See How much memory is available from the HIMEM driver
  281. atxh100:
  282. pmxmssvc 8 ; query freespace available
  283. cmp bl,0 ; Test for error
  284. jnz atxhDone ; No luck - Try DOS
  285. cmp ax,0
  286. je atxhDone
  287. ; cmp ax,cx ; is largest block > allocation desired?
  288. ; jb atxh110 ; no, use largest block
  289. ; mov ax,cx ; yes, use desired alloc
  290. atxh110:
  291. mov dx,ax ; Load reported size of largest free block
  292. mov bx,ax ; Calculate number of bytes available
  293. shl bx,10
  294. shr ax,6 ; AX:BX = available bytes
  295. sub bx,3*CB_MEMHDR ; Adjust for header overhead
  296. sbb ax,0
  297. mov word ptr cbHeapSize,bx ; Save lower order bytes available
  298. mov word ptr [cbHeapSize+2],ax ; Save higher order bytes available
  299. pmxmssvc 9 ; Allocate the largest possible block
  300. cmp ax,0 ; Check for error
  301. jz atxhDone ; HIMEM driver speak with forked tongue
  302. mov hmemHeap,dx ; Save the handle
  303. pmxmssvc 0Ch ; Lock and query address
  304. xchg bx,dx
  305. mov dsegCurrent,0 ; Flag this allocate was not from DOS
  306. cmp ax,0 ; Test result
  307. jnz atxh300 ; Rejoin common code
  308. Trace_Out "AddToXmemHeap: Lock of XMS handle #DX failed."
  309. jmp atxhDone ; Jump on error
  310. atxh300:
  311. call StructureHeap ; Build sentinels and free block
  312. mov ax,selHeapStart ; Remember the high heap start selector
  313. mov selHiHeapStart,ax
  314. ; Done allocating memory.
  315. atxhDone:
  316. cEnd
  317. ; -------------------------------------------------------
  318. ; InitXmemHeap -- This routine will initialize the
  319. ; extended memory heap.
  320. ;
  321. ; Input:
  322. ; Output:
  323. ; Errors:
  324. ; Uses:
  325. ;
  326. assume ds:DGROUP,es:DGROUP,ss:NOTHING
  327. public InitXmemHeap
  328. InitXmemHeap:
  329. ret
  330. IFNDEF WOW_x86
  331. ; -------------------------------------------------------
  332. ; FreeXmemHeap -- This routine gives the xms memory back to
  333. ; the xms driver. The selectors for the heap are not
  334. ; freed. Shortly after we release the heap, the LDT will
  335. ; be reinitialized, and that will free the selectors
  336. ;
  337. public FreeXmemHeap
  338. FreeXmemHeap:
  339. ret ; bugbug
  340. ENDIF
  341. ; -------------------------------------------------------
  342. ; StructureHeap -- This routine creates the sentinel header
  343. ; blocks and a header block for a free object containing
  344. ; the new memory.
  345. ;
  346. ; Input: BX - Most significant part of heap block address
  347. ; DX - Least significant part of heap block address
  348. ;
  349. ; Output: None
  350. ; Errors: Carry flag set if there was not enough memory available
  351. ; Uses: BX, DX
  352. ;
  353. ; NOTE: This routine must be called in protected mode.
  354. ;
  355. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  356. public StructureHeap
  357. StructureHeap proc near
  358. push ax
  359. push cx
  360. push es
  361. push bx ; most significant part of address
  362. push dx ; least significant part of address
  363. ; Allocate selectors for the two sentinel blocks, and the initial free
  364. ; block and link them at the start of the chain.
  365. ;
  366. ; Create the end sentinel
  367. add dx,word ptr cbHeapSize ;Calculate address of end sentinel
  368. adc bx,word ptr [cbHeapSize + 2]
  369. add dx,2*CB_MEMHDR
  370. adc bx,0
  371. call AddSelectorToChain ;Allocate/link the end sentinel
  372. ; Initialize the ending sentinel block.
  373. assume es:MEMHDR
  374. xor ax,ax
  375. mov fBlkStatus,al
  376. mov cselBlkData,al
  377. mov selBlkData,ax
  378. mov selBlkOwner,0FFFFh
  379. mov cx,hmemHeap ; Save handle
  380. mov hBlockHandle,cx
  381. mov cx,dsegCurrent ; Save paragraph count
  382. mov dsegBlock,cx
  383. ; Create the free block
  384. pop dx ; least significant part of address
  385. pop bx ; most significant part of address
  386. add dx,CB_MEMHDR ; Calculate address of Free block
  387. adc bx,0
  388. call AddSelectorToChain ; Allocate and link the Free Block
  389. ; Initialize the header for the free data block.
  390. mov fBlkStatus,al
  391. mov cselBlkData,al
  392. mov selBlkData,ax
  393. mov selBlkOwner,ax
  394. mov cx,word ptr [cbHeapSize]
  395. mov word ptr [cbBlkLen],cx
  396. mov cx,word ptr [cbHeapSize+2]
  397. mov word ptr [cbBlkLen+2],cx
  398. ; Create the starting sentinel
  399. sub dx,CB_MEMHDR ; Calculate address of start sentinel
  400. sbb bx,0
  401. call AddSelectorToChain ; Allocate and link the start sentinel
  402. ; Initialize the starting sentinel block.
  403. mov fBlkStatus,al
  404. mov cselBlkData,al
  405. mov selBlkData,ax
  406. mov selBlkOwner,0FFFEh ;mark it as in use
  407. mov cx,hmemHeap ; Save handle
  408. mov hBlockHandle,cx
  409. mov cx,dsegCurrent ; Save paragraph count
  410. mov dsegBlock,cx
  411. pop es
  412. pop cx
  413. pop ax
  414. ret
  415. StructureHeap endp
  416. ; -------------------------------------------------------
  417. ; AddSelectorToChain -- This function will create a header block at a
  418. ; specified address and link it to the head of the
  419. ; header chain. It is the caller's responsibility
  420. ; to initialize all fields in the header other
  421. ; than the chain link pointers themselves.
  422. ;
  423. ; This function can only be called in protected mode.
  424. ;
  425. ; Input: BX - Most significant part of header address
  426. ; DX - Least significant part of header address
  427. ; Output: ES - selector for the new header
  428. ; Errors: Carry flag set on error
  429. ; Uses: all registers except ES preserved
  430. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  431. public AddSelectorToChain
  432. AddSelectorToChain:
  433. push ax ; Save callers regs
  434. push bx ;
  435. push cx ;
  436. call AllocateSelector ; Get a free selector
  437. jc astcFail ; Jump on error
  438. mov cx,CB_MEMHDR - 1 ;
  439. cCall NSetSegmentDscr,<ax,bx,dx,0,cx,STD_DATA>
  440. mov cx,selHeapStart ; Load old start of chain
  441. jcxz @f
  442. mov es,cx ; Point to old start of chain
  443. assume es:MEMHDR ;
  444. mov selBlkPrev,ax ; Link to new start of chain
  445. @@:
  446. mov es,ax ; Point to new head of chain
  447. mov selBlkNext,cx ; Link it to old head
  448. mov selBlkPrev,0 ; NULL back pointer
  449. mov selBlkHdr,ax ; Block header points to itself
  450. mov selHeapStart,ax ; Store new head of chain
  451. clc ; Flag no error
  452. astcFail:
  453. pop cx ; Restore Users regs
  454. pop bx ;
  455. pop ax ;
  456. ret ; AddSelectorToChain
  457. ; -------------------------------------------------------
  458. ; AllocateXmem32 -- This function will return a 32-bit address and
  459. ; handle of a block of memory allocated in extended
  460. ; memory.
  461. ;
  462. ; Input: BX:CX - Size of block desired
  463. ; DX - Owner of block
  464. ; Output: BX:CX - Address of memory
  465. ; SI:DI - handle of memory
  466. ; Errors: Carry flag set on error
  467. ; Uses:
  468. ; -------------------------------------------------------
  469. public AllocateXmem32
  470. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  471. AllocateXmem32 proc near
  472. FBOP BOP_DPMI, AllocXmem, FastBop
  473. ret
  474. AllocateXmem32 endp
  475. ; -------------------------------------------------------
  476. ; FreeXmem32 -- This function will free a block of extended memory
  477. ; allocated by AllocateXmem.
  478. ;
  479. ; Input: SI:DI - Handle of memory
  480. ; Errors: Carry flag set on error
  481. ; Uses:
  482. ; -------------------------------------------------------
  483. public FreeXmem32
  484. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  485. FreeXmem32 proc near
  486. FBOP BOP_DPMI, FreeXmem, FastBop
  487. ret
  488. FreeXmem32 endp
  489. DXPMCODE ends
  490. DXCODE segment
  491. assume cs:DXCODE
  492. ; -------------------------------------------------------
  493. ; ReleaseLowHeap -- This routine will release the
  494. ; special low memory heap. After this function is
  495. ; called, InitLowHeap must be called again before
  496. ; any other low heap functions can be used.
  497. ;
  498. ; Currently this routine doesn't bother to release
  499. ; selectors used by the blocks in the low heap (like
  500. ; ReleaseXmemHeap does) under the assumption that
  501. ; the DOS extender is about to terminate. If you are
  502. ; really going reinitialize the low heap with InitLowHeap,
  503. ; then you should do more clean up here.
  504. ;
  505. ; Input: none
  506. ; Output: none
  507. ; Errors:
  508. ; Uses: All preserved
  509. ;
  510. ; Note: This routine must be called in real mode!
  511. assume ds:DGROUP,es:DGROUP,ss:NOTHING
  512. public ReleaseLowHeap
  513. ReleaseLowHeap proc near
  514. push ax
  515. push es
  516. mov ax,segLowHeap ;make sure there really is a low heap
  517. or ax,ax
  518. jz rlh90
  519. mov es,ax ;now use DOS to get rid of it
  520. mov ah,49h
  521. pushf
  522. sub sp,8 ; make room for stack frame
  523. push bp
  524. mov bp,sp
  525. push es
  526. push ax
  527. xor ax,ax
  528. mov es,ax
  529. mov [bp + 8],cs
  530. mov [bp + 6],word ptr (offset rlh10)
  531. mov ax,es:[21h*4]
  532. mov [bp + 2],ax
  533. mov ax,es:[21h*4 + 2]
  534. mov [bp + 4],ax
  535. pop ax
  536. pop es
  537. pop bp
  538. retf
  539. rlh10: xor ax,ax ;just to be tidy
  540. mov segLowHeap,ax
  541. mov selLowHeapStart,ax
  542. rlh90:
  543. pop es
  544. pop ax
  545. ret
  546. ReleaseLowHeap endp
  547. ; -------------------------------------------------------
  548. ; ReleaseXmemHeap -- This routine will release memory
  549. ; used by the extended memory heap. After this function
  550. ; is called, no extended memory manager routines can
  551. ; be called except InitXmemHeap.
  552. ;
  553. ; Input:
  554. ; Output:
  555. ; Errors:
  556. ; Uses:
  557. ;
  558. ; Note: Do NOT enable interrupts while in protected mode!
  559. assume ds:DGROUP,es:DGROUP,ss:NOTHING
  560. public ReleaseXmemHeap
  561. ReleaseXmemHeap:
  562. push ax
  563. push bx
  564. push cx
  565. push dx
  566. push ds
  567. push es
  568. SwitchToProtectedMode ; Needed for selector juggling
  569. ifdef MD
  570. call CheckXmemHeap
  571. endif
  572. mov bx,selHeapStart ; Point to the start of the block chain
  573. mov es,bx ;
  574. assume es:MEMHDR ;
  575. ;
  576. ; This is the start of a loop on all blocks. ES and BX both contain the
  577. ; selector for the current block, or zero if at the end of the chain.
  578. rxh100:
  579. or bx,bx ; End of chain?
  580. jz rxhEnd ; Yes - Jump
  581. mov cl,cselBlkData ; Load number of data segments
  582. xor ch,ch ;
  583. jcxz rxh200 ; Jump if nothing to do
  584. mov ax,selBlkData ; Load first data segment
  585. and ax,SELECTOR_INDEX ; Treat like GDT entry for FreeSelector
  586. rxh110:
  587. push ax ; Since it is destroyed by FreeSelector
  588. call FreeSelector ; Free each of the data selectors
  589. pop ax ;
  590. add ax,8 ; Point to the next data descriptor
  591. loop rxh110 ;
  592. ;
  593. ; All data descriptors for this block now free (if there ever were any)
  594. rxh200:
  595. push selBlkNext ; Push pointer to the next block in the chain
  596. push es ; Push the pointer to this one
  597. cmp selBlkOwner,0FFFFh ; Is this an end sentinel ?
  598. jne rxh300 ; No - jump
  599. ;
  600. ; Time to free a HIMEM allocated memory blcok
  601. rxh210:
  602. mov dx,hBlockHandle ;
  603. push dx ; Since the data may move after the unlock
  604. ASSUME es:NOTHING ;
  605. pmxmssvc 0Dh,disable ;unlock the memory block containing the heap
  606. pop dx ;
  607. pmxmssvc 0Ah,disable ;free the block
  608. ;
  609. ; Time to free the header selector.
  610. rxh300:
  611. pop ax ; Retrieve the selector for the current header
  612. pop bx ; Retrieve the selector for the next one
  613. mov es,bx ;
  614. call FreeSelector ; Free the selector for the current header
  615. jmp rxh100 ; Loop for the next block
  616. ;
  617. ; All done
  618. rxhEnd:
  619. mov selHeapStart,0 ; Point to the start of the block chain
  620. ifdef MD
  621. call CheckXmemHeap
  622. endif
  623. SwitchToRealMode ; Restore callers environment
  624. sti ;
  625. pop es
  626. pop ds
  627. pop dx
  628. pop cx
  629. pop bx
  630. pop ax
  631. ret
  632. ; -------------------------------------------------------
  633. DXCODE ends
  634. ; -------------------------------------------------------
  635. subttl Main Routines
  636. page
  637. ; -------------------------------------------------------
  638. DXPMCODE segment
  639. assume cs:DXPMCODE
  640. ; -------------------------------------------------------
  641. ; MAIN MEMORY MANAGEMENT ROUTINES
  642. ; -------------------------------------------------------
  643. ;
  644. ; AllocateLowBlock -- This function will allocate a block
  645. ; of memory from the special low memory heap.
  646. ; If the requested block is larger than 64k, multiple segment
  647. ; descriptors will be allocated, one for each full 64k and one
  648. ; for whatever is left over. When multiple segment descriptors
  649. ; are created, the selectors will differ by 8 for each segment.
  650. ; (i.e. the returned selector accesses the first 64k, add 8 to
  651. ; get to the next 64k, etc.)
  652. ;
  653. ; Input: CX - low word of requested block size
  654. ; DX - high word of requested block size
  655. ; Output: AX - initial selector for the memory block
  656. ; Errors: returns CY set and size of largest free memory block in CX,DX.
  657. ; This can occur either because there isn't a large enough
  658. ; free block in the memory pool, or there isn't a contiguous
  659. ; range of free segment descriptors that is large enough.
  660. ; Uses: AX, all else preserved. Modifies the segment descriptors
  661. ; for the SEL_SCR0 and SEL_SCR1 segments
  662. ;
  663. ; Note: This routine is _very_ similar to AllocateXmemBlock,
  664. ; but just different enough that it's a separate routine.
  665. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  666. public AllocateLowBlock
  667. AllocateLowBlock proc near
  668. push bp
  669. mov bp,sp
  670. sub sp,14
  671. push es
  672. push si
  673. push bx
  674. push cx
  675. push dx
  676. Segm equ word ptr [bp - 2]
  677. StartSel equ word ptr [bp - 4]
  678. Largest equ word ptr [bp - 6]
  679. MemSize equ [bp - 10]
  680. cSelector equ word ptr [bp - 12]
  681. selHeader equ word ptr [bp - 14]
  682. mov word ptr MemSize,cx
  683. mov word ptr MemSize + 2,dx
  684. ;
  685. ; See if we need to use wow kernel to manage low memory
  686. ;
  687. mov ax,word ptr [LowMemAllocFn]
  688. or ax,word ptr [LowMemAllocFn + 2]
  689. je alm3
  690. jmp alm130
  691. ;
  692. ; Round up to the next paragraph
  693. ;
  694. alm3: add cx,15
  695. adc dx,0
  696. and cx,0FFF0h
  697. ;
  698. ; Form a paragraph count
  699. ;
  700. mov bx,cx
  701. shr bx,4
  702. shl dx,12
  703. or bx,dx
  704. ;
  705. ; Add one to make room for the heap header
  706. ;
  707. cmp bx,0ffffh
  708. je alm5 ; won't succed, but get size
  709. inc bx
  710. alm5:
  711. ;
  712. ; Switch to real mode and allocate the memory
  713. ;
  714. SwitchToRealMode
  715. mov ax,4800h
  716. int 21h ; call dos
  717. jnc alm10
  718. mov Segm,ax
  719. mov Largest,bx
  720. mov cx,0
  721. jmp alm20
  722. ;
  723. ; Remember the values returned
  724. ;
  725. alm10: mov Segm,ax
  726. mov cx,1
  727. alm20: SwitchToProtectedMode
  728. cmp cx,0
  729. jne alm40
  730. ;
  731. ; return an error
  732. ;
  733. alm30: mov cx,bx
  734. mov dx,bx
  735. shr dx,12
  736. shl cx,4 ; form bytes available
  737. mov ax,Segm ; actually error code for fail
  738. add sp,4 ; skip cx,dx
  739. stc
  740. jmp alm110
  741. alm40: mov ax,word ptr MemSize + 2
  742. mov bx,word ptr MemSize
  743. or bx, bx
  744. jnz short alm44
  745. or ax, ax
  746. jz short alm45 ; if zero then don't adjust
  747. alm44:
  748. sub bx,1
  749. sbb ax,0 ; go from size to limit
  750. alm45:
  751. mov word ptr MemSize + 2,ax
  752. mov word ptr MemSize,bx
  753. inc ax ; we always want 2 more
  754. inc ax
  755. mov cSelector,ax
  756. xor cx, cx ;allocate from lower range
  757. call AllocateSelectorBlock
  758. jnc alm50
  759. mov ax,8 ; insufficient memory
  760. mov bx,Largest
  761. jmp alm30
  762. alm50: or ax,STD_RING
  763. mov si,ax
  764. mov StartSel,ax
  765. mov ax,word ptr MemSize + 2
  766. mov bx,word ptr MemSize ; ax:bx - block size
  767. mov cx,Segm
  768. mov dx,cx
  769. shr cx,12
  770. shl dx,4 ; cx:dx - block base
  771. ;
  772. ; Set up the first one to have the entire limit
  773. ;
  774. cCall NSetSegmentDscr,<si,cx,dx,ax,bx,STD_DATA>
  775. ;
  776. ; Set up the rest to have 64K limits
  777. ;
  778. dec ax ; already set one
  779. cmp ax,0FFFFh
  780. je alm80
  781. cmp ax,0
  782. je alm70
  783. mov di,0FFFFh
  784. alm60: add si,8
  785. inc cx ; add 64K to base
  786. cCall NSetSegmentDscr,<si,cx,dx,0,di,STD_DATA>
  787. dec ax
  788. cmp ax,0
  789. jne alm60
  790. ;
  791. ; Just one selector left, so set the correct limit
  792. ;
  793. alm70: add si,8
  794. inc cx
  795. cCall NSetSegmentDscr,<si,cx,dx,0,bx,STD_DATA>
  796. ;
  797. ; Set up header
  798. ;
  799. alm80: mov ax,Segm
  800. mov bx,ax
  801. shr ax,12
  802. shl bx,4 ; ax:bx = base of header
  803. add bx,word ptr MemSize
  804. adc ax,word ptr MemSize + 2
  805. add si,8
  806. cCall NSetSegmentDscr,<si,ax,bx,0,CB_MEMHDR,STD_DATA>
  807. ;
  808. ; Set up values in header and add to chain
  809. ;
  810. mov es,si
  811. mov selHeader,si
  812. assume es:MEMHDR
  813. mov [selBlkHdr],si
  814. mov ax,StartSel
  815. mov [selBlkData],ax
  816. mov ax,cSelector
  817. mov [cselBlkData],al
  818. mov ax,selPSPChild
  819. mov [selBlkOwner],ax
  820. mov ax,Segm
  821. mov [hBlockHandle],ax
  822. mov ax,selLowHeapStart
  823. mov [selBlkNext],ax
  824. mov bx,0
  825. mov [selBlkPrev],bx
  826. or ax,ax
  827. jz alm100
  828. mov bx,es
  829. mov es,ax
  830. mov [selBlkPrev],bx
  831. ;
  832. ; set up return values
  833. ;
  834. alm100: mov ax,selHeader
  835. mov selLowHeapStart,ax
  836. mov ax,StartSel
  837. clc
  838. alm105: pop dx
  839. pop cx
  840. alm110: pop bx
  841. pop si
  842. pop es
  843. mov sp,bp
  844. pop bp
  845. ret
  846. alm130: push dx
  847. push cx
  848. call [LowMemAllocFn]
  849. or ax,ax
  850. jz alm140
  851. clc
  852. jmp alm105
  853. alm140: xor cx,cx
  854. stc
  855. add sp,4
  856. jmp alm110
  857. AllocateLowBlock endp
  858. ; -------------------------------------------------------
  859. ; FreeLowBlock -- This function will free the low heap
  860. ; memory block specified by the given selector. It
  861. ; will return the memory block to the free memory pool,
  862. ; and release all selectors used by this block.
  863. ;
  864. ; Input: AX - selector of the data block to free
  865. ; Output: none
  866. ; Errors: returns CY set if invalid selector
  867. ; Uses: AX, all other registers preserved
  868. ; Modifies the descriptor for segment SEL_SCR0
  869. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  870. public FreeLowBlock
  871. FreeLowBlock proc near
  872. push bp
  873. mov bp,sp
  874. sub sp,4
  875. Segm equ word ptr [bp - 2]
  876. HeaderSel equ word ptr [bp - 4]
  877. push es
  878. push bx
  879. push cx
  880. ;
  881. ; See if we need to use the wow kernel to manage memory
  882. ;
  883. mov bx,word ptr [LowMemFreeFn]
  884. or bx,word ptr [LowMemFreeFn + 2]
  885. jz flm5
  886. jmp flm130
  887. ;
  888. ; search for the block to free
  889. ;
  890. flm5: mov bx,selLowHeapStart
  891. flm10: or bx,bx ; any low blocks?
  892. jz flm100
  893. mov es,bx
  894. assume es:MEMHDR
  895. cmp [selBlkData],ax
  896. je flm30 ; found the correct block
  897. mov bx,[selBlkNext]
  898. jmp flm10
  899. ;
  900. ; Unlink the block from the list
  901. ;
  902. flm30: mov ax,es
  903. mov HeaderSel,ax
  904. mov ax,[selBlkPrev]
  905. mov bx,[selBlkNext]
  906. cmp ax,0
  907. je flm40
  908. mov es,ax
  909. mov [selBlkNext],bx
  910. jmp flm50
  911. flm40: mov SelLowHeapStart,bx
  912. flm50: cmp bx,0
  913. je flm60
  914. mov es,bx
  915. mov [selBlkPrev],ax
  916. flm60: mov ax,HeaderSel
  917. mov es,ax
  918. mov ax,[hBlockHandle]
  919. mov Segm,ax
  920. mov ax,[selBlkData]
  921. xor cx,cx
  922. mov cl,[cselBlkData]
  923. push 0
  924. pop es
  925. call FreeSelectorBlock
  926. SwitchToRealMode
  927. mov ax,Segm
  928. mov es,ax
  929. mov ax,4900h
  930. int 21h ; free the memory
  931. push ax ; save return code
  932. jnc flm70
  933. mov cx,0 ; error
  934. jmp flm80
  935. flm70: mov cx,1 ; no error
  936. flm80: SwitchToProtectedMode
  937. pop ax
  938. cmp cx,0
  939. je flm100 ; error path
  940. flm85: clc
  941. flm90: pop cx
  942. pop bx
  943. pop es
  944. mov sp,bp
  945. pop bp
  946. ret
  947. flm100: stc
  948. jmp flm90
  949. flm130: push ax
  950. call [LowMemFreeFn]
  951. or ax,ax
  952. jz flm85
  953. mov ax,9
  954. stc
  955. jmp flm90
  956. FreeLowBlock endp
  957. ; -------------------------------------------------------
  958. ;
  959. ; AllocateXmemBlock -- This function will allocate a block
  960. ; of extended memory and return selectors for accessing it.
  961. ; If the requested block is larger than 64k, multiple segment
  962. ; descriptors will be allocated, one for each full 64k and one
  963. ; for whatever is left over. When multiple segment descriptors
  964. ; are created, the selectors will differ by 8 for each segment.
  965. ; (i.e. the returned selector accesses the first 64k, add 8 to
  966. ; get to the next 64k, etc.)
  967. ;
  968. ; Input: BL - flag controlling allocation of selectors,
  969. ; if 0 - a selector will be allocated for each 64k
  970. ; if != 0 - only one selector will be allocated to
  971. ; the block.
  972. ; CX - low word of requested block size
  973. ; DX - high word of requested block size
  974. ; Output: AX - initial selector for the memory block
  975. ; Errors: returns CY set and size of largest free memory block in CX,DX.
  976. ; This can occur either because there isn't a large enough
  977. ; free block in the memory pool, or there isn't a contiguous
  978. ; range of free segment descriptors that is large enough.
  979. ; Uses: AX, all else preserved. Modifies the segment descriptors
  980. ; for the SEL_SCR0 and SEL_SCR1 segments
  981. ;
  982. ; Notes: Hard coding an int 3 in this routine is fatal. This routine
  983. ; is used to allocate the stack used for exception handling.
  984. ;
  985. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  986. public AllocateXmemBlock
  987. AllocateXmemBlock proc near
  988. axb1: push bp
  989. mov bp,sp
  990. sub sp,20
  991. push es
  992. push bx
  993. push si
  994. push di
  995. push cx
  996. push dx
  997. AllocFlag equ byte ptr [bp - 2]
  998. cSelector equ word ptr [bp - 4]
  999. MemHandle equ [bp - 8]
  1000. MemSize equ [bp - 12]
  1001. MemAddr equ [bp - 16]
  1002. StartSel equ word ptr [bp - 18]
  1003. HeaderSel equ word ptr [bp - 20]
  1004. mov AllocFlag,bl
  1005. mov word ptr MemSize,cx
  1006. mov word ptr MemSize + 2,dx
  1007. mov word ptr MemHandle,0
  1008. mov word ptr MemHandle + 2,0
  1009. ;
  1010. ; Save room for header
  1011. ;
  1012. add cx,16
  1013. adc dx,0
  1014. mov bx,dx
  1015. mov dx, selPSPChild
  1016. call AllocateXmem32
  1017. jnc axb40
  1018. jmp axb130
  1019. axb40: mov word ptr MemAddr,cx
  1020. mov word ptr MemAddr + 2,bx
  1021. mov word ptr MemHandle,di
  1022. mov word ptr MemHandle + 2,si
  1023. ;
  1024. ; Change size to limit
  1025. ;
  1026. mov ax,word ptr MemSize + 2
  1027. mov bx,word ptr MemSize
  1028. sub bx,1
  1029. sbb ax,0 ; size -> limit
  1030. mov word ptr MemSize,bx
  1031. mov word ptr MemSize + 2,ax
  1032. ;
  1033. ; Figure out how many selectors to allocate
  1034. ;
  1035. cmp AllocFlag,0
  1036. jne axb50
  1037. inc ax
  1038. jmp axb60
  1039. axb50: mov ax,1
  1040. ;
  1041. ; Add one additional for the header block
  1042. ;
  1043. axb60: inc ax
  1044. mov cSelector,ax
  1045. ;
  1046. ; Allocate the selectors
  1047. ;
  1048. xor cx,cx ; allocate from lower range
  1049. call AllocateSelectorBlock
  1050. jnc axb65
  1051. jmp axb120
  1052. axb65: or ax,STD_RING
  1053. mov StartSel,ax
  1054. ;
  1055. ; Set up the first selector to have the entire limit
  1056. ;
  1057. mov di,cSelector
  1058. mov si,ax
  1059. mov ax,word ptr MemSize + 2
  1060. mov bx,word ptr MemSize
  1061. mov cx,word ptr MemAddr + 2
  1062. mov dx,word ptr MemAddr
  1063. add dx,16 ; room for header
  1064. adc cx,0
  1065. cCall NSetSegmentDscr,<si,cx,dx,ax,bx,STD_DATA>
  1066. dec di
  1067. dec ax
  1068. add si,8
  1069. cmp di,1
  1070. je axb90
  1071. ;
  1072. ; Set up the rest with 64K limits
  1073. ;
  1074. axb70: cmp ax,0
  1075. je axb80
  1076. inc cx
  1077. cCall NSetSegmentDscr,<si,cx,dx,0,0FFFFh,STD_DATA>
  1078. dec ax
  1079. add si,8
  1080. jmp axb70
  1081. ;
  1082. ; Set up the last one with the remaining limit
  1083. ;
  1084. axb80: inc cx
  1085. cCall NSetSegmentDscr,<si,cx,dx,0,bx,STD_DATA>
  1086. add si,8
  1087. ;
  1088. ; Set up Header selector
  1089. ;
  1090. axb90: mov ax,word ptr MemAddr + 2
  1091. mov bx,word ptr MemAddr
  1092. cCall NSetSegmentDscr,<si,ax,bx,0,CB_MEMHDR,STD_DATA>
  1093. mov HeaderSel,si
  1094. ;
  1095. ; Set up header
  1096. ;
  1097. mov es,si
  1098. assume es:MEMHDR
  1099. mov [selBlkHdr],si
  1100. mov ax,StartSel
  1101. mov [selBlkData],ax
  1102. mov ax,cSelector
  1103. mov [cselBlkData],al
  1104. mov ax,selPSPChild
  1105. mov [selBlkOwner],ax
  1106. mov ax,MemHandle
  1107. mov [hBlockHandle],ax
  1108. mov ax,word ptr MemHandle + 2
  1109. mov [dsegBlock],ax ; use for high half handle
  1110. mov ax,selHiHeapStart
  1111. mov [selBlkNext],ax
  1112. mov bx,0
  1113. mov [selBlkPrev],bx
  1114. or ax,ax
  1115. jz axb100
  1116. mov bx,es
  1117. mov es,ax
  1118. mov [selBlkPrev],bx
  1119. axb100: mov ax,HeaderSel
  1120. mov selHiHeapStart,ax
  1121. ;
  1122. ; return information to the caller
  1123. ;
  1124. clc
  1125. mov ax,StartSel
  1126. pop dx
  1127. pop cx
  1128. axb110: pop di
  1129. pop si
  1130. pop bx
  1131. pop es
  1132. mov sp,bp
  1133. pop bp
  1134. ret
  1135. ;
  1136. ; Error
  1137. ;
  1138. axb120: mov dx,word ptr MemHandle
  1139. or dx,word ptr MemHandle + 2
  1140. jz axb130
  1141. mov di,word ptr MemHandle
  1142. mov si,word ptr MemHandle + 2
  1143. FBOP BOP_DPMI, FreeXmem, FastBop
  1144. ;
  1145. ; Get largest free block
  1146. ;
  1147. axb130: pmxmssvc 08h
  1148. mov dx,ax
  1149. mov cx,ax
  1150. shl cx,10
  1151. shr dx,6
  1152. add sp,4 ; skip cx,dx on stack
  1153. stc
  1154. jmp axb110
  1155. AllocateXmemBlock endp
  1156. ; -------------------------------------------------------
  1157. ; FreeXmemBlock -- This function will free the extended
  1158. ; memory block specified by the given selector. It
  1159. ; will return the memory block to the free memory pool,
  1160. ; and release all selectors used by this block.
  1161. ;
  1162. ; Input: AX - selector of the data block to free
  1163. ; Output: none
  1164. ; Errors: returns CY set if invalid selector
  1165. ; Uses: AX, all other registers preserved
  1166. ; Modifies the descriptor for segment SEL_SCR0
  1167. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  1168. public FreeXmemBlock
  1169. FreeXmemBlock:
  1170. fxb1: push bp
  1171. mov bp,sp
  1172. sub sp,6
  1173. HeaderSel equ word ptr [bp - 2]
  1174. MemHandle equ [bp - 6]
  1175. push es
  1176. push bx
  1177. push si
  1178. push di
  1179. push dx
  1180. push cx
  1181. ;
  1182. ; search for the block to free
  1183. ;
  1184. mov bx,selHiHeapStart
  1185. fxb10: or bx,bx ; any hi blocks?
  1186. jnz fxb20
  1187. jmp fxb100
  1188. fxb20: mov es,bx
  1189. assume es:MEMHDR
  1190. cmp [selBlkData],ax
  1191. je fxb30 ; found the correct block
  1192. mov bx,[selBlkNext]
  1193. jmp fxb10
  1194. ;
  1195. ; Unlink the block from the list
  1196. ;
  1197. fxb30: mov ax,es
  1198. mov HeaderSel,ax
  1199. mov ax,[selBlkPrev]
  1200. mov bx,[selBlkNext]
  1201. cmp ax,0
  1202. je fxb40
  1203. mov es,ax
  1204. mov [selBlkNext],bx
  1205. jmp fxb50
  1206. fxb40: mov SelHiHeapStart,bx
  1207. fxb50: cmp bx,0
  1208. je fxb60
  1209. mov es,bx
  1210. mov [selBlkPrev],ax
  1211. fxb60: mov ax,HeaderSel
  1212. mov es,ax
  1213. mov dx,[dsegBlock] ; high half handle
  1214. mov word ptr MemHandle + 2,dx
  1215. mov dx,[hBlockHandle]
  1216. mov word ptr MemHandle,dx
  1217. ;
  1218. ; Free the selectors
  1219. ;
  1220. mov ax,[selBlkData]
  1221. xor cx,cx
  1222. mov cl,[cselBlkData]
  1223. push 0
  1224. pop es
  1225. assume es:nothing
  1226. call FreeSelectorBlock
  1227. mov si,word ptr MemHandle + 2
  1228. mov di,word ptr MemHandle
  1229. call FreeXmem32
  1230. clc
  1231. fxb90: pop cx
  1232. pop dx
  1233. pop di
  1234. pop si
  1235. pop bx
  1236. pop es
  1237. mov sp,bp
  1238. pop bp
  1239. ret
  1240. fxb100: stc
  1241. jmp fxb90
  1242. ; -------------------------------------------------------
  1243. ; ModifyXmemBlock -- This function will modify the size
  1244. ; of the specified extended memory block to the new
  1245. ; size specified by CX,DX. If the block is being
  1246. ; shrunk, the new size must be at least CB_HDRSIZ bytes
  1247. ; smaller than the old size, or nothing is done.If the
  1248. ; block grows beyond the next 64k boundary,
  1249. ; it may be necessary to allocate another segment
  1250. ; descriptor for it. If this is not possible, the grow
  1251. ; will fail.
  1252. ;
  1253. ; Input: AX - segment selector for the data block to modify
  1254. ; BL - flag controlling allocation of selectors to block,
  1255. ; if 0 - selectors will be allocated for each 64k
  1256. ; if != 0 - only one selector is allocated to block
  1257. ; CX - low word of new desired size
  1258. ; DX - high word of new desired size
  1259. ; Output: none
  1260. ; Errors: CY set if unable to accomplish the request.
  1261. ; returns error code in AX.
  1262. ; CX,DX will be set to the largest possible size that the
  1263. ; block could be modified to have
  1264. ; Uses: AX,CX,DX,Flags
  1265. assume ds:DGROUP,es:NOTHING
  1266. public ModifyXmemBlock
  1267. ModifyXmemBlock proc near
  1268. mxb1: push bp
  1269. mov bp,sp
  1270. sub sp,20
  1271. HeaderSel equ word ptr [bp - 2]
  1272. AllocFlags equ byte ptr [bp - 4]
  1273. MemSize equ [bp - 8]
  1274. MemAddr equ [bp - 12]
  1275. Success equ word ptr [bp - 14]
  1276. cSelector equ word ptr [bp - 16]
  1277. BlockHandle equ word ptr [bp - 20]
  1278. push es
  1279. push bx
  1280. push cx
  1281. push dx
  1282. mov word ptr MemSize + 2,dx
  1283. mov word ptr MemSize,cx
  1284. mov AllocFlags,bl
  1285. mov Success,1
  1286. ;
  1287. ; Search for the block to resize
  1288. ;
  1289. mov bx,selHiHeapStart
  1290. mxb10: or bx,bx ; any hi blocks?
  1291. jnz mxb15
  1292. jmp mxb140
  1293. mxb15: mov es,bx
  1294. assume es:MEMHDR
  1295. cmp [selBlkData],ax
  1296. je mxb30 ; found the correct block
  1297. mov bx,[selBlkNext]
  1298. jmp mxb10
  1299. ;
  1300. ; Calculate the number of selectors needed
  1301. ;
  1302. mxb30: mov HeaderSel,es
  1303. test AllocFlags,1
  1304. jne mxb40
  1305. sub cx, 1 ; size -> limit
  1306. sbb dx,0
  1307. inc dl
  1308. jmp mxb50
  1309. mxb40: mov dl,1
  1310. mxb50: inc dl ; always need 1 more
  1311. ;
  1312. ; See if we have enough selectors
  1313. ;
  1314. cmp dl,[cselBlkData]
  1315. jna mxb55
  1316. jmp mxb120
  1317. mxb55: and dl,0ffh
  1318. mov cSelector,dx
  1319. mov dx,[dsegBlock]
  1320. mov word ptr BlockHandle + 2,dx
  1321. mov dx,[hBlockHandle]
  1322. mov word ptr BlockHandle,dx
  1323. mov bx,word ptr MemSize + 2
  1324. mov cx,word ptr MemSize
  1325. add cx,010h
  1326. adc bx,0
  1327. mov si,word ptr BlockHandle + 2
  1328. mov di,word ptr BlockHandle
  1329. FBOP BOP_DPMI, ReallocXmem, FastBop
  1330. jnc mxb60
  1331. mov Success,0
  1332. mxb60: mov word ptr MemAddr,cx
  1333. mov word ptr MemAddr + 2,bx
  1334. mov word ptr BlockHandle,di
  1335. mov word ptr BlockHandle + 2,si
  1336. ;
  1337. ; Fix the base of the Header selector
  1338. ;
  1339. mov bx,word ptr MemAddr + 2
  1340. mov dx,word ptr MemAddr
  1341. mov ax,HeaderSel
  1342. call SetSegmentAddress
  1343. mov es,ax
  1344. ;
  1345. ; Fix the handle (may have changed
  1346. ;
  1347. mov dx,word ptr BlockHandle
  1348. mov [hBlockHandle],dx
  1349. mov dx,word ptr BlockHandle + 2
  1350. mov [dsegBlock],dx
  1351. ;
  1352. ; Change size to limit
  1353. ;
  1354. mov ax,word ptr MemSize + 2
  1355. mov bx,word ptr MemSize
  1356. sub bx,1
  1357. sbb ax,0 ; size -> limit
  1358. mov word ptr MemSize,bx
  1359. mov word ptr MemSize + 2,ax
  1360. ;
  1361. ; Set up the first selector to have the entire limit
  1362. ;
  1363. mov di,cSelector
  1364. mov si,[selBlkData]
  1365. mov ax,word ptr MemSize + 2
  1366. mov bx,word ptr MemSize
  1367. mov cx,word ptr MemAddr + 2
  1368. mov dx,word ptr MemAddr
  1369. add dx,16 ; room for header
  1370. adc cx,0
  1371. cCall NSetSegmentDscr,<si,cx,dx,ax,bx,STD_DATA>
  1372. dec di
  1373. dec ax
  1374. add si,8
  1375. cmp di,1
  1376. je mxb100
  1377. ;
  1378. ; Set up the rest with 64K limits
  1379. ;
  1380. mxb80: cmp ax,0
  1381. je mxb90
  1382. inc cx
  1383. cCall NSetSegmentDscr,<si,cx,dx,0,0FFFFh,STD_DATA>
  1384. dec ax
  1385. add si,8
  1386. jmp mxb80
  1387. ;
  1388. ; Set up the last one with the remaining limit
  1389. ;
  1390. mxb90: inc cx
  1391. cCall NSetSegmentDscr,<si,cx,dx,0,bx,STD_DATA>
  1392. add si,8
  1393. ;
  1394. ; Were we successfull?
  1395. ;
  1396. mxb100: cmp Success,1
  1397. jne mxb130
  1398. clc
  1399. pop dx
  1400. pop cx
  1401. mxb110: pop bx
  1402. pop es
  1403. mov sp,bp
  1404. pop bp
  1405. ret
  1406. ;
  1407. ; We had an error, not enough selectors. Figure out how large
  1408. ; it could have been
  1409. ;
  1410. mxb120: xor dx,dx
  1411. xor cx,cx
  1412. mov dl,[cselBlkData]
  1413. dec dl ; don't count header sel
  1414. mov ax,8
  1415. add sp,4 ; pop cx,dx
  1416. stc
  1417. jmp mxb110
  1418. ;
  1419. ; We had an error calling xms. Get the largest block
  1420. ;
  1421. mxb130: pmxmssvc 08h
  1422. mov cx,ax ; convert to bytes
  1423. mov dx,ax
  1424. shl cx,10
  1425. shr dx,6
  1426. mov ax,8
  1427. add sp,4
  1428. stc
  1429. jmp mxb110
  1430. ;
  1431. ; We had an error, invalid selector
  1432. ;
  1433. mxb140: mov ax,9
  1434. add sp,4
  1435. stc
  1436. jmp mxb110
  1437. ModifyXmemBlock endp
  1438. ret
  1439. ;
  1440. ; -------------------------------------------------------
  1441. subttl Utility Routines
  1442. page
  1443. ; -------------------------------------------------------
  1444. ; UTIITY ROUTINES
  1445. ; -------------------------------------------------------
  1446. ; -------------------------------------------------------
  1447. ; CalculateMaximumSegmentSpace -- This function will see if there
  1448. ; are enough free segments available
  1449. ; to expand a block of memory.
  1450. ; If not it returns with carry set
  1451. ; and the maximum space available.
  1452. ;
  1453. ; Input; ES - segment selector for the data block to modify
  1454. ; CX - low word of new desired size
  1455. ; DX - high word of new desired size
  1456. ;
  1457. ; Output CX - / If CY set: The maximum available
  1458. ; DX - \ If CY not set: Unchanged
  1459. ; Errors: CY set if unable to accomplish the request.
  1460. ; CX,DX will be set to the largest possible size that the
  1461. ; block could be modified to have
  1462. ; Uses: AX,CX,DX,Flags
  1463. assume ds:DGROUP,es:MEMHDR
  1464. public CalculateMaximumSegmentSpace
  1465. CalculateMaximumSegmentSpace:
  1466. push bx
  1467. push es
  1468. xor bx,bx
  1469. mov bl,cselBlkData ; Allocated selector count
  1470. shl bx,3 ; Convert to byte offset
  1471. add bx,selBlkData ; Add starting data selector offset
  1472. and bx,SELECTOR_INDEX ; Treat it as a GDT selector
  1473. mov es,selGDT ; Base the global descriptor table
  1474. assume es:NOTHING ;
  1475. ; Count through the immediately following selectors
  1476. cmssLoop:
  1477. cmp bx,word ptr bpgdt ; Off the end of the GDT ?
  1478. ja cmssOutOfSelectors ; Yes - Jump
  1479. cmp word ptr es:[bx].arbSegAccess,0 ; Is the next selector free ?
  1480. jne cmssOutOfSelectors ; No - jump
  1481. ; Point to the next selector
  1482. add bx,8 ; Increment to next selector
  1483. jnc cmssLoop ; Try the next one
  1484. ; BX points to the first following selector which is not free
  1485. cmssOutOfSelectors:
  1486. pop es ; Recover block header segment
  1487. assume es:MEMHDR
  1488. push dx ; Subtract base selector address
  1489. mov dx,selBlkData
  1490. and dx,SELECTOR_INDEX
  1491. sub bx,dx
  1492. pop dx
  1493. shr bx,3 ; Number of contiguous selectors available
  1494. cmp bx,dx ; Is it enough ?
  1495. jb cmssNotEnough ; No - jump
  1496. jne cmssOK ; Yes - jump
  1497. or cx,cx ; Don't know - Look at less significant part
  1498. jnz cmssNotEnough ; Yes it will fit after all - jump
  1499. ; Not enough free selectors
  1500. cmssNotEnough:
  1501. mov dx,bx ; Put max available in CX&DX
  1502. xor cx,cx ;
  1503. stc ; Flag error
  1504. jmp short cmssExit ; Leave
  1505. ;
  1506. ; There are enough selectors to satisfy the request
  1507. cmssOK:
  1508. clc ; Reset the error flag
  1509. ;
  1510. ; All Done
  1511. cmssExit:
  1512. pop bx ; Restore registers
  1513. ret ; CalculateMaximumSegmentSpace
  1514. ; -------------------------------------------------------
  1515. ; CalculateMaximumSpace -- This function will see if there
  1516. ; is room to expand a block of memory.
  1517. ; If not it returns with carry set
  1518. ; and the maximum space available.
  1519. ;
  1520. ; Input: AL - check selectors yes/no flag - 0 = yes, !0 = no
  1521. ; ES - segment selector for the data block to modify
  1522. ; CX - low word of new desired size
  1523. ; DX - high word of new desired size
  1524. ; Output: AX - Strategy used: 0 = expand into same block
  1525. ; 1 = expand into next block
  1526. ; 2 = expand into next and previous blocks
  1527. ; 3 = allocate a new block and transfer data
  1528. ; 4 = move lower and higher blocks
  1529. ; CX - / If CY set: The maximum available
  1530. ; DX - \ If CY not set: Unchanged
  1531. ; Errors: CY set if unable to accomplish the request.
  1532. ; CX,DX will be set to the largest possible size that the
  1533. ; block could be modified to have
  1534. ; Uses: AX,CX,DX,Flags
  1535. assume ds:DGROUP,es:MEMHDR
  1536. public CalculateMaximumSpace
  1537. CalculateMaximumSpace proc near
  1538. push bp
  1539. mov bp,sp
  1540. push es
  1541. push cx ; Save required length
  1542. push dx
  1543. push ax ; Save segment/selector flag
  1544. mov cx,word ptr [cbBlkLen] ; Load present length
  1545. mov dx,word ptr [cbBlkLen+2] ;
  1546. mov ax,0 ; Load strategy code
  1547. cmp dx,word ptr [bp - 6] ; Compare available with needed
  1548. jb cms90 ; Jump if it doesn't fit
  1549. ja cmsOKa ; Jump if it fits
  1550. cmp cx,word ptr [bp - 4] ;
  1551. jb cms90 ;
  1552. cmsOKa:
  1553. jmp cmsOK
  1554. ; There is not enough room in the current block. See if the following
  1555. ; one is free
  1556. cms90:
  1557. mov es,[selBlkNext] ; Point to the following block
  1558. cmp [selBlkOwner],0 ; Is it in use?
  1559. jnz cmsFail ; Yes - cannot use it
  1560. add cx,CB_MEMHDR ; Add the header of next block
  1561. adc dx,0
  1562. add cx,word ptr [cbBlkLen] ; Add the body of the next block
  1563. adc dx,word ptr [cbBlkLen+2];
  1564. mov ax,1 ; Load strategy code
  1565. cmp dx,word ptr [bp - 6] ; Compare available with needed
  1566. ja cmsOK ; Jump if it fits
  1567. cmp cx,word ptr [bp - 4] ;
  1568. jae cmsOK ;
  1569. ; Cannot expand. The max available is in CX&DX
  1570. cmsFail:
  1571. add sp,6 ; Throw away requested size, and strat
  1572. pop es ; Point to original header
  1573. cmp byte ptr [bp-8],0 ; Should we check the # of
  1574. jz @f ; available selectors?
  1575. stc
  1576. jmp short cmsExit
  1577. @@:
  1578. call CalculateMaximumSegmentSpace ;Check for enough selectors
  1579. stc ;Flag error
  1580. jmp short cmsExit
  1581. ; Expand will succeed. Strategy number is in ax
  1582. cmsOK:
  1583. add sp,2 ; discard strategy
  1584. pop dx ; Restore requested size
  1585. pop cx ;
  1586. cms900:
  1587. pop es ; Point to original header
  1588. cmp byte ptr [bp-8],0 ; Should we check the # of
  1589. jz @f ; available selectors?
  1590. clc
  1591. jmp short cmsExit
  1592. @@:
  1593. call CalculateMaximumSegmentSpace ;Check for enough selectors
  1594. cmsExit:
  1595. pop bp
  1596. ret
  1597. CalculateMaximumSpace endp
  1598. ; -------------------------------------------------------
  1599. ;
  1600. ;
  1601. ; CombineFreeBlocks -- This routine is used when freeing
  1602. ; an extended memory block. It will examine the previous
  1603. ; and following blocks to see if they are free also, and
  1604. ; combine them into a single larger block if so.
  1605. ;
  1606. ; Input: AX - selector of segment descriptor for the block
  1607. ; Output: AX - selector for new free memory block
  1608. ; Errors: none
  1609. ; Uses: AX, ES modified, all other registers preserved
  1610. ;
  1611. ; NOTE: This routine may free the segment descriptor for the
  1612. ; entry block as part of the process of combining blocks.
  1613. ; The original entry value may no longer be used after
  1614. ; calling this routine. If access to the block header
  1615. ; for the free segment is still needed, you must use
  1616. ; the value returned in AX to access it.
  1617. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  1618. public CombineFreeBlocks
  1619. CombineFreeBlocks:
  1620. push bx
  1621. push dx
  1622. ;
  1623. mov bx,ax ;save entry value in BX
  1624. ;
  1625. ; Look at the previous block and see if it is free.
  1626. mov es,bx ;look at block header of entry block
  1627. assume es:MEMHDR
  1628. mov es,[selBlkPrev] ;look at block header of previous block
  1629. cmp [selBlkOwner],0 ;is it in use?
  1630. jnz cfrb30 ;if so, continue on
  1631. ;
  1632. ; The previous memory block is free. We need to combine it with the
  1633. ; current one.
  1634. mov ax,bx
  1635. call SpliceBlocks
  1636. mov bx,es
  1637. ;
  1638. ; Look at the following block and see if it is free.
  1639. cfrb30: mov es,bx ;look at the current lower free block
  1640. assume es:MEMHDR
  1641. mov es,[selBlkNext] ;look at the following block
  1642. cmp [selBlkOwner],0 ;is it in use?
  1643. jnz cfrb90
  1644. ;
  1645. ; The following memory block is free. We need to combine it with the
  1646. ; current one.
  1647. mov ax,es
  1648. mov es,bx
  1649. call SpliceBlocks
  1650. ;
  1651. ; All done
  1652. cfrb90: mov ax,bx
  1653. pop dx
  1654. pop bx
  1655. ret
  1656. ; -------------------------------------------------------
  1657. ; SpliceBlocks -- This routine is used by CombineFreeBlocks
  1658. ; to perform the actual combination of two adjacent free
  1659. ; blocks. The space occupied by the upper block is assigned
  1660. ; to the lower block, and the upper block is then eliminated.
  1661. ;
  1662. ; Input: AX - selector to the upper block
  1663. ; ES - selector to the lower block
  1664. ; Output: none
  1665. ; Errors: none
  1666. ; Uses: AX, DX modified
  1667. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  1668. SpliceBlocks:
  1669. push ds
  1670. mov ds,ax
  1671. assume ds:NOTHING ;DS points at upper block
  1672. ;ES points at lower block
  1673. push ax
  1674. ;
  1675. mov dx,word ptr ds:[cbBlkLen]
  1676. mov ax,word ptr ds:[cbBlkLen+2]
  1677. add dx,CB_MEMHDR
  1678. adc ax,0
  1679. add word ptr es:[cbBlkLen],dx
  1680. adc word ptr es:[cbBlkLen+2],ax
  1681. mov ax,ds:[selBlkNext]
  1682. mov es:[selBlkNext],ax
  1683. mov ds,ax ;DS points at block following entry block
  1684. mov ds:[selBlkPrev],es
  1685. ;
  1686. pop ax
  1687. pop ds
  1688. call FreeSelector ;release the segment descriptor for the
  1689. ; upper block
  1690. ret
  1691. ; -------------------------------------------------------
  1692. ; FindFreeBlock -- This function will search the extended
  1693. ; memory heap looking for a free memory block of at
  1694. ; least the requested size.
  1695. ;
  1696. ; Input: CX - low word of requested block size
  1697. ; DX - high word or requested block size
  1698. ; Output: AX - selector for the block header of the free block
  1699. ; cbHeapBlkMax - size of largest free block found
  1700. ; cbHeapFreeSpace - total free space seen
  1701. ; Errors: Returns CY set if large enough free block not found.
  1702. ; If that happens, then cbHeapBlkMax contains the size of the
  1703. ; largest free block, and cbHeapFreeSpace contains the total
  1704. ; of all free blocks.
  1705. ; Uses: AX modified, all other registers preserved.
  1706. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  1707. public FindFreeBlock
  1708. FindFreeBlock:
  1709. push cx
  1710. push dx
  1711. push es
  1712. ;
  1713. mov word ptr [cbHeapBlkMax],0
  1714. mov word ptr [cbHeapBlkMax+2],0
  1715. mov word ptr [cbHeapFreeSpace],0
  1716. mov word ptr [cbHeapFreeSpace+2],0
  1717. ;
  1718. cmp selHeapStart,0 ;
  1719. jz ffrb80 ; No heap - no allocate - jump
  1720. mov es,selHeapStart ; ES points at the beginning of the heap
  1721. assume es:MEMHDR
  1722. ;
  1723. ; Is the current memory block free?
  1724. ffrb20:
  1725. cmp selBlkOwner,0 ;if the block isn't free, try the next one
  1726. jnz ffrb26
  1727. ;
  1728. ; Accumulate size into free space count.
  1729. mov ax,word ptr [cbBlkLen]
  1730. add word ptr [cbHeapFreeSpace],ax
  1731. mov ax,word ptr [cbBlkLen+2]
  1732. adc word ptr [cbHeapFreeSpace+2],ax
  1733. ;
  1734. ; Update our view of what the largest free block is.
  1735. mov ax,word ptr [cbBlkLen+2]
  1736. cmp ax,word ptr [cbHeapBlkMax+2]
  1737. jc ffrb26
  1738. jnz ffrb22
  1739. mov ax,word ptr [cbBlkLen]
  1740. cmp ax,word ptr [cbHeapBlkMax]
  1741. jc ffrb26
  1742. ffrb22: mov ax,word ptr [cbBlkLen+2]
  1743. mov word ptr [cbHeapBlkMax+2],ax
  1744. mov ax,word ptr [cbBlkLen]
  1745. mov word ptr [cbHeapBlkMax],ax
  1746. ;
  1747. ; Check the size of this memory block to see if it is large enough.
  1748. ffrb24: cmp dx,word ptr [cbBlkLen+2]
  1749. jc ffrb40
  1750. jnz ffrb26
  1751. cmp cx,word ptr [cbBlkLen]
  1752. jna ffrb40
  1753. ;
  1754. ; Go to the next block in the heap
  1755. ffrb26:
  1756. cmp selBlkNext,0 ; End of chain?
  1757. jz ffrb80 ; Yes - jump
  1758. mov es,[selBlkNext]
  1759. jmp ffrb20
  1760. ;
  1761. ; Found a free block that is large enough
  1762. ffrb40: mov ax,es
  1763. clc
  1764. jmp short ffrb90
  1765. ;
  1766. ; Didn't find one, return error.
  1767. ffrb80: stc
  1768. ;
  1769. ; All done
  1770. ffrb90: pop es
  1771. pop dx
  1772. pop cx
  1773. ret
  1774. ; -------------------------------------------------------
  1775. ; FreeSpace -- This function is used to find out how
  1776. ; much free space there is in the heap, plus that
  1777. ; which is potentially available from an XMS driver.
  1778. ;
  1779. ; Input: None
  1780. ; Output: AX:DX -- Total free space
  1781. ; BX:CX -- Largest free block
  1782. ; Errors: none
  1783. ; Uses: AX, all else preserved
  1784. ;
  1785. ; History:10/09/90 -- earleh wrote it.
  1786. ;
  1787. cProc FreeSpace,<NEAR,PUBLIC>,
  1788. cBegin
  1789. ;
  1790. ; Call xms to get free memory space
  1791. ;
  1792. pmxmssvc 08h
  1793. ;
  1794. ; convert to bytes
  1795. ;
  1796. mov bx,dx
  1797. mov dx,ax
  1798. mov cx,bx
  1799. shl dx,10
  1800. shr ax,6
  1801. shl cx,10
  1802. shr bx,6
  1803. ;
  1804. ; account for heap header
  1805. ;
  1806. sub dx,CB_MEMHDR
  1807. sbb ax,0
  1808. sub cx,CB_MEMHDR
  1809. sbb bx,0
  1810. ret
  1811. cEnd
  1812. ; -------------------------------------------------------
  1813. ; SplitBlock -- This function will split the specified
  1814. ; memory block into two blocks, with the first one
  1815. ; being the specified size, and the second one containing
  1816. ; the remaining space.
  1817. ;
  1818. ; Input: AX - selector of block header for memory block to split
  1819. ; CX - low word of requested size
  1820. ; DX - high word of requested size
  1821. ; Output: none
  1822. ; Errors: none
  1823. ; Uses: AX, all else preserved
  1824. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  1825. public SplitBlock
  1826. SplitBlock:
  1827. push bx
  1828. push cx
  1829. push dx
  1830. push si
  1831. push es
  1832. ;
  1833. mov es,ax
  1834. assume es:MEMHDR
  1835. ;
  1836. ; We are going to need a segment descriptor for the remainder block
  1837. ; when we do the split. Make sure that we can allocate the selector
  1838. ; now, before we change anything.
  1839. call AllocateSelector
  1840. jnc spbl20 ;
  1841. jmp spbl90 ;get out if error
  1842. spbl20: mov si,ax ;save selector in SI for later
  1843. ;
  1844. ; Adjust the size of the current block and figure the size of the
  1845. ; remainder.
  1846. xchg cx,word ptr [cbBlkLen] ;store the new block length
  1847. xchg dx,word ptr [cbBlkLen+2] ; and get the old block length
  1848. push cx ;Save the original size for recovery
  1849. push dx
  1850. sub cx,word ptr [cbBlkLen] ;compute the amount of space
  1851. sbb dx,word ptr [cbBlkLen+2] ; remaining in the block
  1852. sub cx,CB_MEMHDR ;also account for the new block header
  1853. sbb dx,0
  1854. jc spbl25 ;Jump if not enough memory to split
  1855. jnz spbl30 ;if there is some remaining memory, then
  1856. cmp cx,0 ; we have additional work to do
  1857. jnz spbl30
  1858. ;
  1859. ; There is no remaining memory. Free the selector that we allocated
  1860. ; earlier and then get out.
  1861. spbl25: mov ax,si
  1862. pop dx ;Recover old size
  1863. pop cx
  1864. mov word ptr [cbBlkLen],cx ;restore the old block length
  1865. mov word ptr [cbBlkLen+2],dx
  1866. call FreeSelector
  1867. jmp spbl90
  1868. ;
  1869. ; We need to create a segment descriptor for the new memory block header
  1870. ; for the remainder block.
  1871. spbl30: add sp,4 ;Dispose of unneeded recovery data
  1872. push cx ;save memory block length for later
  1873. push dx
  1874. mov ax,es ;selector of current memory header
  1875. call GetSegmentAddress
  1876. mov cx,CB_MEMHDR - 1
  1877. add dx,word ptr [cbBlkLen] ;bump by size of current block
  1878. adc bx,word ptr [cbBlkLen+2]
  1879. add dx,CB_MEMHDR ;plus size of block header
  1880. adc bx,0
  1881. mov ax,si
  1882. cCall NSetSegmentDscr,<ax,bx,dx,0,cx,STD_DATA>
  1883. pop dx
  1884. pop cx
  1885. ;
  1886. ; Now, we need to build a new memory block header for the remainder of
  1887. ; the original block. CX,DX has the size of the new block.
  1888. push ds
  1889. ;
  1890. mov ds,si
  1891. assume ds:NOTHING ;DS points at new block header
  1892. assume es:NOTHING ;ES points at old block header
  1893. xor ax,ax
  1894. mov ds:[fBlkStatus],al
  1895. mov ds:[cselBlkData],al
  1896. mov ds:[selBlkData],ax
  1897. mov ds:[selBlkOwner],ax
  1898. mov ds:[selBlkHdr],ds
  1899. mov word ptr ds:[cbBlkLen],cx
  1900. mov word ptr ds:[cbBlkLen+2],dx
  1901. mov ds:[selBlkPrev],es
  1902. mov ax,es:[selBlkNext]
  1903. mov ds:[selBlkNext],ax
  1904. mov es:[selBlkNext],si
  1905. mov ds,ax ;DS points at following block
  1906. mov ds:[selBlkPrev],si
  1907. cmp ds:[selBlkOwner],0 ;is it in use?
  1908. ;
  1909. pop ds
  1910. assume ds:DGROUP
  1911. jnz spbl90 ;Jump if the following block is not free
  1912. ;
  1913. ; The following memory block is free. We need to combine it with the
  1914. ; current one.
  1915. mov es,si
  1916. call SpliceBlocks
  1917. ;
  1918. ; All done
  1919. spbl90: pop es
  1920. pop si
  1921. pop dx
  1922. pop cx
  1923. pop bx
  1924. ret
  1925. ; -------------------------------------------------------
  1926. ; GetBlockHeader -- This function will return the selector
  1927. ; for the block header of the specified memory data
  1928. ; block.
  1929. ;
  1930. ; Input: AX - selector of the data block
  1931. ; Output: AX - selector of the block header
  1932. ; Errors: returns CY set if the entry selector doesn't point
  1933. ; to a valid data block
  1934. ; Uses: AX, all other registers preserved
  1935. ; Modifies the descriptor for segment SEL_SCR0
  1936. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  1937. GetBlockHeader:
  1938. push bx
  1939. push cx
  1940. push dx
  1941. push es
  1942. push ax ;save entry value for later
  1943. mov bx,SEL_SCR0 or STD_TBL_RING
  1944. call DupSegmentDscr ;duplicate input descriptor to scratch
  1945. mov ax,bx
  1946. call GetSegmentAddress
  1947. sub dx,CB_MEMHDR ;backup to supposed header
  1948. sbb bx,0
  1949. mov cx,CB_MEMHDR-1 ; has the proper limit!
  1950. cCall NSetSegmentDscr,<ax,bx,dx,0,cx,STD_DATA>
  1951. mov es,ax
  1952. assume es:MEMHDR
  1953. pop cx ;recover data block selector
  1954. cmp cx,[selBlkData] ;does the header point back to the
  1955. jz gtbh50 ; data block.
  1956. stc ;if not, then what were given wasn't a
  1957. jmp short gtbh90 ; selector to a memory block
  1958. gtbh50: mov ax,[selBlkHdr] ;get the real selector to the header
  1959. gtbh90: pop es
  1960. pop dx
  1961. pop cx
  1962. pop bx
  1963. ret
  1964. ; -------------------------------------------------------
  1965. ; DisposeBlock -- This routine will free all segment
  1966. ; descriptors associated with the specified memory block,
  1967. ; and remove the block header from the heap list.
  1968. ;
  1969. ; Input: AX - selector of block to dispose
  1970. ; Output: none
  1971. ; Errors: none
  1972. ; Uses: All registers preserved
  1973. ;
  1974. ; NOTE: This routine frees selectors for the specified memory block.
  1975. ; If this selector is already in a segment register when this
  1976. ; routine is called a GP fault will occur it that segment
  1977. ; register is later saved or restored. Also, any references to
  1978. ; memory using that segment register might destroy random data
  1979. ; in memory.
  1980. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  1981. public DisposeBlock
  1982. DisposeBlock:
  1983. push cx
  1984. push si
  1985. push di
  1986. push es
  1987. ;
  1988. ; Remove the block header from the heap list.
  1989. mov es,ax ;header selector to ES
  1990. mov si,es:[selBlkNext] ;SI points to following block
  1991. mov di,es:[selBlkPrev] ;DI points to previous block
  1992. mov es,di ;ES points to previous block
  1993. mov es:[selBlkNext],si ;previous block points to following block
  1994. mov es,si ;ES points to following block
  1995. mov es:[selBLkPrev],di ;following block points back to prev. block
  1996. ;
  1997. ; Free any data block descriptors associated with this memory object.
  1998. mov es,ax
  1999. cmp es:[selBlkOwner],0
  2000. jz dspb40
  2001. xor ch,ch
  2002. mov cl,es:[cselBlkData]
  2003. mov ax,es:[selBlkData]
  2004. and ax,SELECTOR_INDEX ;treat as GDT FreeSelectorBlock
  2005. call FreeSelectorBlock
  2006. ;
  2007. ; Free the descriptor for the block header.
  2008. dspb40: mov ax,es
  2009. pop es
  2010. call FreeSelector
  2011. ;
  2012. ; All done
  2013. dspb90: pop di
  2014. pop si
  2015. pop cx
  2016. ret
  2017. ; -------------------------------------------------------
  2018. ; SetUpDataDescriptors -- This function will initialize
  2019. ; all of the data segment descriptors associated with
  2020. ; a block. Those that should point to data will be
  2021. ; initialized accordingly. Those corresponding to
  2022. ; addresses beyond the allocated data will be initialized
  2023. ; as not present. If insufficient data segment
  2024. ; descriptors have been allocated, an attempt
  2025. ; will be made to allocate them. If this fails an error
  2026. ; occurs.
  2027. ;
  2028. ; Input: AX - Selector of the header segment.
  2029. ;
  2030. ; Output: None
  2031. ;
  2032. ; Errors: Returns CY set if not enough data segment descriptors
  2033. ; are available.
  2034. ;
  2035. ; Uses: Segment descriptor table is modified. Possibly the
  2036. ; data segment count in the header is modified.
  2037. ; No registers affected.
  2038. ;
  2039. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  2040. public SetUpDataDescriptors
  2041. SetUpDataDescriptors:
  2042. push es
  2043. push si
  2044. push bx
  2045. push cx
  2046. push dx
  2047. push ax
  2048. mov es,ax
  2049. mov si,ax ;save header segment for dup
  2050. assume es:MEMHDR
  2051. mov bx,selBlkData ;Starting data selector index
  2052. and bx,SELECTOR_INDEX
  2053. xor cx,cx
  2054. mov cl,cselBlkData ;Load segment count
  2055. inc cx
  2056. mov dx,word ptr es:[cbBlkLen+2] ;Full data segment count
  2057. mov es,selGDT
  2058. assume es:NOTHING
  2059. sudd30:
  2060. or dx,dx ;is this the last segment?
  2061. jnz sudd35
  2062. pop es ;Get the header segment
  2063. push es
  2064. cmp word ptr es:[cbBlkLen],0 ;Test partial length
  2065. mov es,selGDT ;Rebase the global descriptor table
  2066. jnz sudd35 ;Jump if the partial length is 0
  2067. jmp sudd60
  2068. sudd35: loop short sudd40 ;Out of segments?
  2069. xchg bx,ax
  2070. call RemoveFreeDescriptor ;Attempt to get segment
  2071. xchg bx,ax
  2072. jnc sudd37
  2073. jmp sudd80
  2074. sudd37: inc cx
  2075. sudd40: mov ax,si
  2076. call DupSegmentDscr ; replicate the previous seg (in si)
  2077. mov si,bx
  2078. ; Set the DPL of allocated blocks to user DPL
  2079. ifndef WOW_x86
  2080. mov es:[si].arbSegAccess,STD_DATA
  2081. else
  2082. push ax
  2083. xor ax,ax
  2084. mov ah,es:[si].cbLimitHi386
  2085. or ax,STD_DATA
  2086. cCall NSetSegmentAccess,<si,ax>
  2087. pop ax
  2088. endif
  2089. ; Increment the segment start address past the previous one
  2090. cmp es:[si].cbLimit,CB_MEMHDR-1 ; Is this the first block?
  2091. jne sudd41 ; No - jump
  2092. ifndef WOW_x86
  2093. add es:[si].adrBaseLow,CB_MEMHDR ; bump segment start to point
  2094. adc es:[si].adrBaseHigh,0 ;past the block header
  2095. else
  2096. push ax
  2097. push dx
  2098. mov ax,es:[si].adrBaseLow
  2099. mov dl,es:[si].adrBaseHigh
  2100. mov dh,es:[si].adrbBaseHi386
  2101. add ax,CB_MEMHDR
  2102. adc dx,0
  2103. cCall NSetSegmentBase,<si,dx,ax>
  2104. pop dx
  2105. pop ax
  2106. endif
  2107. jmp short sudd42
  2108. ifndef WOW_x86
  2109. sudd41: add es:[si].adrBaseHigh,1 ; bump segment start by 64k
  2110. else
  2111. sudd41: push ax
  2112. push dx
  2113. mov ax, es:[si].adrBaseLow
  2114. mov dl, es:[si].adrBaseHigh
  2115. mov dh, es:[si].adrbBaseHi386
  2116. inc dx
  2117. cCall NSetSegmentBase,<si,dx,ax>
  2118. pop dx
  2119. pop ax
  2120. endif
  2121. ; Set the segment length
  2122. sudd42: add bx,8 ; Offset of next segment descriptor
  2123. or dx,dx ; Was this a partial segment?
  2124. jnz sudd45 ; jump if not
  2125. ;
  2126. ; We are at the partial (<64k) chunk at the end.
  2127. pop es ;Get the header segment
  2128. push es
  2129. mov dx,word ptr es:[cbBlkLen] ; Segment length
  2130. dec dx ; Last legal offset
  2131. mov es,selGDT
  2132. mov es:[si].cblimit,dx ; Store in segment descriptor
  2133. ifdef WOW_x86
  2134. cCall NSetSegmentLimit,<si>
  2135. endif
  2136. jmp sudd60 ; All valid data segs now exist
  2137. sudd45:
  2138. mov es:[si].cbLimit,0FFFFh ;set segment limit at 64k
  2139. ifdef WOW_x86
  2140. cCall NSetSegmentLimit,<si>
  2141. endif
  2142. dec dx ; On to the next data segment
  2143. jmp sudd30
  2144. ;
  2145. ; Invalidate remaining segments
  2146. sudd50: mov ax,si
  2147. call DupSegmentDscr ; replicate the previous one and
  2148. mov si,bx
  2149. mov word ptr es:[si].arbSegAccess,0 ; Invalidate the segment
  2150. add bx,8 ; Offset of next segment descriptor
  2151. sudd60: loop sudd50
  2152. ;
  2153. ; All done
  2154. clc
  2155. jmp short sudd90
  2156. ;
  2157. ; Allocate of a segment descriptor failed.
  2158. sudd80: pop ax ;Header Segment
  2159. mov es,ax ;
  2160. mov dx,es:selBlkData ;Calculate # segments
  2161. and dx,SELECTOR_INDEX ; successfully allocated
  2162. sub bx,dx
  2163. shr bx,3 ;Succesfully allocated
  2164. mov es:[cselBlkData],bl ;Store new value
  2165. mov dx,bx ;Return max allocatable space
  2166. mov cx,0 ;
  2167. add sp,4 ;Pop redundant stack data
  2168. stc ;Flag error
  2169. jmp short sudd100 ;Join common exit code
  2170. ;
  2171. ; Tidy up
  2172. sudd90: pop ax ;Header segment
  2173. mov es,ax
  2174. mov dx,es:selBlkData ;Calculate # segments
  2175. and dx,SELECTOR_INDEX
  2176. sub bx,dx
  2177. shr bx,3
  2178. mov es:[cselBlkData],bl ;Store new value
  2179. pop dx
  2180. pop cx
  2181. sudd100:
  2182. pop bx
  2183. pop si
  2184. pop es
  2185. ret
  2186. ;
  2187. ifdef MD
  2188. ; -------------------------------------------------------
  2189. ; CheckXmemHeap -- This routine will check the integrity
  2190. ; of the chain of block headers.
  2191. ;
  2192. ; Input: NONE
  2193. ; Output: None
  2194. ; Errors: INT3 If an error is found
  2195. ; Uses: All registers preserved
  2196. ;
  2197. ; NOTE: This routine must be called in protected mode.
  2198. assume ds:DGROUP,es:NOTHING,ss:NOTHING
  2199. public CheckXmemHeap
  2200. CheckXmemHeap:
  2201. push bp
  2202. mov bp,sp
  2203. pushf
  2204. push bx
  2205. push cx
  2206. push dx
  2207. push es
  2208. xor cx,cx
  2209. mov dx,cx
  2210. mov bx,selHeapStart ; Load start of chain
  2211. cxmh100:
  2212. or bx,bx ;
  2213. jnz cxmh101
  2214. jmp cxmh200 ;
  2215. cxmh101:
  2216. mov es,bx ;
  2217. assume es:MEMHDR ;
  2218. cmp selBlkHdr,bx ;
  2219. je cxmh110 ;
  2220. int 3
  2221. jmp cxmh200
  2222. ;; Debug_Out "CheckXmemHeap: Block header does not point to block header!"
  2223. cxmh110:
  2224. cmp selBlkPrev,dx ;
  2225. je cxmh120 ;
  2226. int 3
  2227. jmp cxmh200
  2228. ;; Debug_Out "CheckXmemHeap: Previous block does not point to previous block!"
  2229. cxmh120:
  2230. mov dx,bx ;
  2231. mov bx,selBlkNext ;
  2232. loop cxmh100 ;
  2233. int 3
  2234. ;; Debug_Out "CheckXmemHeap: Can't find end of arena chain!"
  2235. cxmh200:
  2236. pop es
  2237. pop dx
  2238. pop cx
  2239. pop bx
  2240. popf
  2241. pop bp
  2242. ret
  2243. endif
  2244. ; -------------------------------------------------------
  2245. ; FreeMemByOwner -- This routine frees all of the mem
  2246. ; blocks that belong to the specified owner.
  2247. ;
  2248. ; Input: bx = owner
  2249. ; Output: none
  2250. ; Uses: ax
  2251. ;
  2252. ; Note: We have to start at the beginning of the heap
  2253. ; after we free a block, because the free may
  2254. ; coalesce the heap, and the selector for the
  2255. ; next block may no longer be correct. We know we
  2256. ; are done when we have traversed the entire heap,
  2257. ; and not found a block to free.
  2258. assume ds:DGROUP, es:nothing, ss:nothing
  2259. public FreeMemByOwner
  2260. FreeMemByOwner:
  2261. push es
  2262. push cx
  2263. cmp bx,0 ; owner is free owner??
  2264. je fbo40
  2265. ; First traverse xmem heap
  2266. push selHeapStart
  2267. mov ax,selHiHeapStart
  2268. mov selHeapStart,ax
  2269. call FreeHiMemByOwnerW
  2270. call FreeLowMemByOwnerW
  2271. pop selHeapStart
  2272. fbo40:
  2273. pop cx
  2274. pop es
  2275. ret
  2276. FreeHiMemByOwnerW:
  2277. fhbow10: mov ax,selHiHeapStart
  2278. fhbow20: cmp ax,0
  2279. je @f
  2280. lar cx, ax ;is this a valid selector?
  2281. jz fhbow25 ;yes, go ahead
  2282. @@:
  2283. ret
  2284. fhbow25: mov es,ax
  2285. assume es:MEMHDR
  2286. cmp selBlkOwner,bx
  2287. jne fhbow30
  2288. mov ax,selBlkDAta
  2289. push 0
  2290. pop es
  2291. call FreeXmemBlock
  2292. jmp fhbow10 ; check again.
  2293. fhbow30: mov ax,selBlkNext ; check next block
  2294. jmp fhbow20
  2295. FreeLowMemByOwnerW:
  2296. flbow10: mov ax,selLowHeapStart
  2297. flbow20: cmp ax,0
  2298. je @f
  2299. lar cx, ax ;is this a valid selector?
  2300. jz flbow25 ;yes, go ahead
  2301. @@:
  2302. ret
  2303. flbow25: mov es,ax
  2304. assume es:MEMHDR
  2305. cmp selBlkOwner,bx
  2306. jne flbow30
  2307. mov ax,selBlkData
  2308. push 0
  2309. pop es
  2310. call FreeLowBlock
  2311. jmp flbow10 ; check again.
  2312. flbow30: mov ax,selBlkNext ; check next block
  2313. jmp flbow20
  2314. ; -------------------------------------------------------
  2315. ; -------------------------------------------------------
  2316. ; -------------------------------------------------------
  2317. ; -------------------------------------------------------
  2318. ; -------------------------------------------------------
  2319. DXPMCODE ends
  2320. ;
  2321. ;****************************************************************
  2322. end