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.

562 lines
23 KiB

  1. ;**************************************************************************
  2. ;* walk286.ASM
  3. ;*
  4. ;* Assembly support code for the KRNL286 global heap routines
  5. ;* for TOOLHELP.DLL
  6. ;*
  7. ;**************************************************************************
  8. INCLUDE TOOLPRIV.INC
  9. PMODE32 = 0
  10. PMODE = 1
  11. SWAPPRO = 0
  12. INCLUDE WINKERN.INC
  13. ;** External functions
  14. externNP HelperVerifySeg
  15. externNP HelperHandleToSel
  16. externNP HelperPDBtoTDB
  17. externNP HelperSegLen
  18. ;** Functions
  19. sBegin CODE
  20. assumes CS,CODE
  21. ; Walk286Count
  22. ;
  23. ; Returns the number of blocks in the given list
  24. cProc Walk286Count, <PUBLIC,NEAR>, <di>
  25. parmW wFlags
  26. cBegin
  27. mov es,hMaster ;Segment of master block
  28. mov ax,wFlags ;Get the flag value
  29. shr ax,1 ;Check for GLOBAL_LRU
  30. jc W2C_LRU ;Bit set, must be LRU
  31. shr ax,1 ;Check for GLOBAL_FREE
  32. jc W2C_Free ;Must be free
  33. ;Must be GLOBAL_ALL
  34. ;** Get total object count
  35. mov ax,es:[hi_count] ;Get heap count
  36. inc ax ;Bump to include first sentinel
  37. jmp SHORT W2C_End ;Get out
  38. ;** Get LRU object count
  39. W2C_LRU:
  40. mov ax,es:[gi_lrucount] ;Get the LRU count
  41. jmp SHORT W2C_End ;Get out
  42. ;** Get Free list object count
  43. W2C_Free:
  44. mov ax,es:[gi_free_count] ;Get free count
  45. jmp SHORT W2C_End ;Get out
  46. ;** Return the result in AX
  47. W2C_End:
  48. cEnd
  49. ; Walk286First
  50. ;
  51. ; Returns a handle to the first block in the 286 global heap.
  52. cProc Walk286First, <PUBLIC,NEAR>, <di>
  53. parmW wFlags
  54. cBegin
  55. mov es,hMaster ;Segment of master block
  56. mov ax,wFlags ;Get the flag value
  57. shr ax,1 ;Check for GLOBAL_LRU
  58. jc W2F_LRU ;Bit set, must be LRU
  59. shr ax,1 ;Check for GLOBAL_FREE
  60. jc W2F_Free ;Must be free
  61. ;Must be GLOBAL_ALL
  62. ;** Get first object in complete heap (wFlags == GLOBAL_ALL)
  63. mov ax,es:[hi_first] ;Get handle of first arena header
  64. jmp SHORT W2F_End ;Get out
  65. ;** Get first object in LRU list
  66. W2F_LRU:
  67. mov ax,es:[gi_lrucount] ;Get the number of objects
  68. or ax,ax ;Are there any objects?
  69. je W2F_End ;No, return NULL
  70. inc es:[gi_lrulock] ;No LRU sweeping for awhile
  71. inc wLRUCount ;Keep a count of this
  72. mov ax,es:[gi_lruchain] ;Get a pointer to the first item
  73. jmp SHORT W2F_End ;Done
  74. ;** Get first object in Free list
  75. W2F_Free:
  76. mov ax,es:[gi_free_count] ;Get the number of objects
  77. or ax,ax ;Are there any objects?
  78. jz W2F_End ;No, return NULL
  79. mov es,es:[hi_first] ;Get the first object
  80. mov ax,es:[ga_freenext] ;Skip to the first free block
  81. ;Fall through to the return
  82. ;** Return the result in AX (return DX = NULL)
  83. W2F_End:
  84. xor dx,dx ;Clear high word
  85. cEnd
  86. ; Walk286
  87. ;
  88. ; Takes a pointer to a block and returns a GLOBALENTRY structure
  89. ; full of information about the block. If the block pointer is
  90. ; NULL, looks at the first block. The last field in the GLOBALENTRY
  91. ; structure is used to chain to the next block and is thus used to walk
  92. ; the heap.
  93. cProc Walk286, <PUBLIC,NEAR>, <di,si,ds>
  94. parmD dwBlock
  95. parmD lpGlobal
  96. parmW wFlags
  97. cBegin
  98. ;** Set up to build public structure
  99. mov es,WORD PTR dwBlock ;Point to this block
  100. lds si,lpGlobal ;Point to the GLOBALENTRY structure
  101. ;** Fill public structure
  102. mov ax,es:[ga_handle] ;Get the handle of the block
  103. mov [si].ge_hBlock,ax ;Put in public structure
  104. mov ax,es:[ga_size] ;Get the size of the block (LOWORD)
  105. mov dx,ax ;Clear high word
  106. shl ax,4 ;Left shift DX:AX by 4
  107. shr dx,16-4
  108. mov WORD PTR [si].ge_dwBlockSize,ax ;Put in public structure
  109. mov WORD PTR [si].ge_dwBlockSize + 2,dx ;Put in public structure
  110. mov ax,es:[ga_owner] ;Owning task of block
  111. mov [si].ge_hOwner,ax ;Put in public structure
  112. xor ah,ah ;No upper BYTE
  113. mov al,es:[ga_count] ;Lock count (moveable segments)
  114. mov [si].ge_wcLock,ax ;Put in public structure
  115. mov WORD PTR [si].ge_wcPageLock,0 ;Zero the page lock count
  116. mov al,es:[ga_flags] ;BYTE of flags
  117. xor ah,ah ;No upper BYTE
  118. mov [si].ge_wFlags,ax ;Put in public structure
  119. mov ax,es:[ga_next] ;Put next pointer in structure
  120. mov WORD PTR [si].ge_dwNext,ax
  121. mov WORD PTR [si].ge_dwNext + 2,0
  122. ;** Use DPMI to compute linear address of selector
  123. mov ax,6 ;Get Segment Base Address
  124. mov bx,es ;Get the segment value
  125. int 31h ;Call DPMI
  126. mov WORD PTR [si].ge_dwAddress,dx ;Save linear address
  127. mov WORD PTR [si].ge_dwAddress + 2,cx
  128. ;** If this is a data segment, get local heap information
  129. mov ax,[si].ge_hBlock ;Get the handle
  130. cCall Walk286VerifyLocHeap
  131. mov [si].ge_wHeapPresent,TRUE ;Flag that there's a heap
  132. jnc W2_10 ;There really is no heap
  133. mov [si].ge_wHeapPresent,FALSE ;Flag that there's no heap
  134. W2_10:
  135. ;** If the owner is a PDB, translate this to the TDB
  136. mov bx,[si].ge_hOwner ;Get the owner
  137. cCall HelperHandleToSel, <bx> ;Translate to selector
  138. mov bx,ax ;Get the selector in BX
  139. cCall HelperVerifySeg, <ax,2> ;Must be two bytes long
  140. or ax,ax ;Is it?
  141. jz W2_15 ;No.
  142. push es ;Save ES for later
  143. mov es,bx ;Point to possible PDB block
  144. cmp es:[0],20CDh ;Int 20h is first word of PDB
  145. jnz W2_12 ;Nope, don't mess with this
  146. mov ax,bx ;Pass parameter in AX
  147. cCall HelperPDBtoTDB ;Get the corresponding TDB
  148. or ax,ax ;Was one found?
  149. jz W2_11 ;No.
  150. mov [si].ge_hOwner,ax ;Make the owner the TDB instead
  151. W2_11: or [si].ge_wFlags,GF_PDB_OWNER ;Flag that a PDB owned block
  152. W2_12: pop es ;Restore ES
  153. W2_15:
  154. ;** Check for this being the last item in both lists
  155. mov ax,es ;Get the current pointer
  156. cmp ax,es:[ga_next] ;See if we're at the end
  157. jne W2_20 ;No
  158. mov WORD PTR [si].ge_dwNext,0 ;NULL the next pointer
  159. mov WORD PTR [si].ge_dwNext + 2,0
  160. W2_20: mov ax,es ;Get current pointer
  161. mov cx,wFlags ;Get the flags back
  162. cCall NextLRU286 ;Get next LRU list pointer or 0
  163. mov WORD PTR [si].ge_dwNextAlt,ax
  164. mov WORD PTR [si].ge_dwNextAlt + 2,0
  165. W2_End:
  166. cEnd
  167. ; Walk286Handle
  168. ;
  169. ; Finds an arena pointer given a block handle
  170. cProc Walk286Handle, <PUBLIC,NEAR>, <di,si,ds>
  171. parmW hBlock
  172. cBegin
  173. mov ax,hBlock ;Get the block handle
  174. cCall HelperHandleToSel, <ax> ;Convert to selector
  175. cCall SelToArena286 ;Get the arena pointer
  176. jnc W2H_10 ;Must be OK
  177. xor ax,ax ;Return a 0L
  178. xor dx,dx
  179. jmp SHORT W2H_End ;Error in conversion, get out
  180. W2H_10: mov ax,bx ;Get the low word
  181. xor dx,dx ;No high word
  182. W2H_End:
  183. cEnd
  184. ; WalkLoc286Count
  185. ;
  186. ; Returns the number of blocks in the given local heap
  187. cProc WalkLoc286Count, <PUBLIC,NEAR>, <di>
  188. parmW hHeap
  189. cBegin
  190. ;** Verify that it has a local heap
  191. mov ax, hHeap ;Get the block
  192. cCall Walk286VerifyLocHeap ;Verify it
  193. jnc LC_10 ;It's OK
  194. xor ax,ax ;No heap
  195. jmp SHORT LC_End ;Get out
  196. LC_10:
  197. ;** Point to the block
  198. mov ax,hHeap ;Get the heap block
  199. cCall HelperHandleToSel, <ax> ;Convert it to a selector
  200. mov es,ax ;Use ES to point to it
  201. mov bx,es:[6] ;Get a pointer to the HeapInfo struct
  202. ;** Get the number of blocks
  203. mov ax,es:[bx].hi_count ;Get the count
  204. LC_End:
  205. cEnd
  206. ; WalkLoc286First
  207. ;
  208. ; Returns a handle to the first block in the 286 global heap.
  209. cProc WalkLoc286First, <PUBLIC,NEAR>, <di>
  210. parmW hHeap
  211. cBegin
  212. ;** Verify that the given global block has a local heap
  213. mov ax, hHeap ;Get the block
  214. cCall Walk286VerifyLocHeap ;Verify it
  215. jnc LF_10 ;It's OK
  216. xor ax,ax ;No heap
  217. jmp SHORT LF_End ;Get out
  218. LF_10:
  219. ;** Point to the global block
  220. mov ax,hHeap ;Get the heap block
  221. cCall HelperHandleToSel, <ax> ;Convert it to a selector
  222. mov es,ax ;Use ES to point to it
  223. mov bx,es:[6] ;Get a pointer to the HeapInfo struct
  224. ;** Get the first block and return it
  225. mov ax,WORD PTR es:[bx].hi_first ;Get the first block
  226. LF_End:
  227. cEnd
  228. ; WalkLoc286
  229. ;
  230. ; Takes a pointer to a block and returns a GLOBALENTRY structure
  231. ; full of information about the block. If the block pointer is
  232. ; NULL, looks at the first block. The last field in the GLOBALENTRY
  233. ; structure is used to chain to the next block and is thus used to walk
  234. ; the heap.
  235. cProc WalkLoc286, <PUBLIC,NEAR>, <di,si,ds>
  236. parmW wBlock
  237. parmD lpLocal
  238. parmW hHeap
  239. cBegin
  240. ;** Verify that it has a local heap
  241. mov ax, hHeap ;Get the block
  242. cCall Walk286VerifyLocHeap ;Verify it
  243. jnc LW_10 ;It's OK
  244. jmp LW_End ;Get out
  245. LW_10:
  246. ;** Get variables from the TOOLHELP DGROUP
  247. mov ax,_DATA ;Get the variables first
  248. mov ds,ax ;Point to our DS
  249. mov bx,hUserHeap ;BX=User's heap block
  250. mov cx,hGDIHeap ;CX=GDI's heap block
  251. ;** Point to the heap
  252. mov ax,hHeap ;Get the heap block
  253. cCall HelperHandleToSel, <ax> ;Convert it to a selector
  254. mov es,ax ;Use ES to point to it
  255. lds di,lpLocal ;Point to the LOCALENTRY structure
  256. mov [di].le_wHeapType,NORMAL_HEAP ;In case we don't match below...
  257. cmp bx,hHeap ;User's heap?
  258. jnz LW_3 ;No
  259. mov [di].le_wHeapType,USER_HEAP ;Yes
  260. jmp SHORT LW_5 ;Skip on
  261. LW_3: cmp cx,hHeap ;GDI's heap?
  262. jnz LW_5 ;No
  263. mov [di].le_wHeapType,GDI_HEAP ;Yes
  264. LW_5:
  265. mov si,wBlock ;Get the address of the block
  266. ;** Get information about the given block
  267. mov bx,es:[si].la_handle ;Get the handle
  268. mov [di].le_hHandle,bx ;Save in the public structure
  269. mov ax,si ;Get block address
  270. add ax,la_fixedsize ;Skip fixed size local arena
  271. mov [di].le_wAddress,ax ;Save the block address
  272. mov ax,es:[si].la_next ;Get the address of the next block
  273. mov [di].le_wNext,ax ;Save the next pointer
  274. sub ax,si ;Compute the size
  275. sub ax,SIZE LocalArena ;Don't count arena size
  276. mov [di].le_wSize,ax ;Save in public structure
  277. mov ax,es:[si].la_prev ;Get the flags
  278. and ax,3 ;Mask out all but flags
  279. mov [di].le_wFlags,ax ;Save in structure
  280. ;** Moveable arenas are bigger and have a lock count to get
  281. test al,LA_MOVEABLE ;Block has a handle iff it's moveable
  282. jz SHORT LW_NoHandle ;No handle info
  283. sub [di].le_wSize, (SIZE LocalArena) - la_fixedsize
  284. add [di].le_wAddress, (SIZE LocalArena) - la_fixedsize
  285. xor ah,ah ;Clear upper word
  286. mov al,es:[bx].lhe_count ;Get lock count
  287. mov [di].le_wcLock,ax ;Save it
  288. jmp SHORT LW_20 ;Skip no handle info
  289. LW_NoHandle:
  290. mov ax, [di].le_wAddress ;Handle of fixed block is real offset
  291. mov [di].le_hHandle, ax
  292. mov [di].le_wcLock,0
  293. LW_20:
  294. ;** See if it's the end
  295. cmp [di].le_wNext,si ;Loop pointer?
  296. jnz LW_End ;Nope
  297. mov [di].le_wNext,0 ;Set a zero pointer
  298. LW_End:
  299. cEnd
  300. ; Walk286VerifyLocHeap
  301. ;
  302. ; Verifies that the given global block points to a data segment
  303. ; with a local heap.
  304. ;
  305. ; Call:
  306. ; AX = Block handle or selector
  307. ; Return:
  308. ; Carry flag set iff NOT a local heap segment
  309. ;
  310. ; Destroys all registers except AX, ESI, EDI, DS, and ES
  311. cProc Walk286VerifyLocHeap, <PUBLIC,NEAR>, <es,si,di>
  312. cBegin
  313. ;** Convert to a handle
  314. cCall HelperHandleToSel, <ax>
  315. ;** Verify the selector
  316. push ax ;Save the parameter
  317. mov bx,SIZE LocalInfo ;Get the size
  318. cCall HelperVerifySeg, <ax,bx> ;Check the selector
  319. or ax,ax ;Is it valid?
  320. pop ax ;Restore parameter
  321. jnz VLH_SelOK ;Yes.
  322. stc ;Set error flag
  323. jmp SHORT VLH_End ;Get out
  324. VLH_SelOK:
  325. ;** Check data segment to see if it has a local heap
  326. mov es,ax ;Point to the local block with ES
  327. cCall HelperSegLen, <ax> ;Get the length of the heap
  328. or ax,ax ;Check for error
  329. jz VLH_NoHeap ;Get out on error
  330. mov cx,ax ;Use CX for comparisons
  331. cmp cx,8 ;At least 8 bytes long?
  332. ja VLH_10 ;Yes
  333. stc ;No -- set error flag and get out
  334. jmp SHORT VLH_End
  335. VLH_10: mov bx,es:[6] ;Get offset to HeapInfo struct
  336. or bx,bx ;If NULL, no local heap
  337. jz VLH_NoHeap ;Get out
  338. sub cx,bx ;See if HeapInfo is beyond segment
  339. jbe VLH_NoHeap
  340. sub cx,li_sig + 2 ;Compare against last structure mem
  341. jbe VLH_NoHeap
  342. cmp es:[bx].li_sig,LOCALHEAP_SIG ;Make sure the signature matches
  343. jne VLH_NoHeap ;Doesn't match
  344. clc ;Must be a heap!
  345. jmp SHORT VLH_End
  346. VLH_NoHeap:
  347. stc ;Set error flag
  348. VLH_End:
  349. cEnd
  350. ;** Private helper functions
  351. ; SelToArena286
  352. ;
  353. ; Finds the arena entry for the given selector or handle.
  354. ; The arena entry is stored 16 bytes before the block in linear
  355. ; address space.
  356. ;
  357. ; Caller: AX = Selector
  358. ; Returns: BX = Arena entry
  359. ; Trashes everything except segment registers and AX
  360. ; Carry set on error
  361. cProc SelToArena286, <NEAR>, <es,ds,ax>
  362. cBegin
  363. ;** Convert to a handle
  364. cCall HelperHandleToSel, <ax>
  365. ;** Verify selector
  366. push ax ;Save the parameter
  367. cCall HelperVerifySeg, <ax,1> ;Check the selector
  368. or ax,ax ;Is it valid?
  369. pop ax ;Restore parameter
  370. jnz STA_SelOK ;Must be
  371. stc ;Nope. Set error flag and exit
  372. jmp SHORT STA_End
  373. STA_SelOK:
  374. ;** If this is Win30StdMode, we're in the old KRNL286 which used
  375. ;* an arcane method of finding the arena. If that's the case
  376. ;** here, handle it seperately.
  377. mov bx,_DATA ;Get the static data segment
  378. mov ds,bx
  379. test wTHFlags,TH_WIN30STDMODE ;3.0 Std Mode?
  380. jnz STA_OldKRNL286 ;Yes
  381. mov bx,segKernel ;Get the KERNEL variable segment
  382. mov es,bx
  383. mov bx,npwSelTableLen ;Get the pointer
  384. mov dx,es:[bx] ;Get the selector table length
  385. mov bx,npdwSelTableStart ;Get the start of the sel table
  386. mov bx,es:[bx] ;Get the linear offset (32 bits)
  387. mov es,hMaster ;Point to the arena table
  388. and al,not 7 ;Clear the RPL bits for table lookup
  389. shr ax,2 ;Convert to WORD offset
  390. cmp ax,dx ;Check to see if off the end of table
  391. jb STA_InTable ;It's in the table
  392. stc ;Set error flag--not in table
  393. jmp SHORT STA_End ;Get out
  394. STA_InTable:
  395. add bx,ax ;Add the selector offset
  396. mov bx,es:[bx] ;Do the sel table indirection
  397. clc ;BX now points to arena segment
  398. jmp SHORT STA_End ;Skip the old stuff
  399. STA_OldKRNL286:
  400. mov bx,ax ;Selector in BX
  401. mov ax,6 ;DPMI function 6, Get Seg Base Addr
  402. int 31h ;Call DPMI
  403. sub dx,10h ;Move back 16 bytes
  404. sbb cx,0 ; (this is a linear address)
  405. mov ax,7 ;DPMI function 7, Set Seg Base Addr
  406. mov bx,wSel ;Use our roving selector
  407. int 31h ;Call DPMI
  408. mov ax,8 ;DPMI function 8, Set Seg Limit
  409. xor cx,cx ;No upper byte
  410. mov dx,16 ;Just 16 bytes
  411. int 31h ;Call DPMI
  412. mov ax,9 ;DPMI function 9, Set Access Rights
  413. mov cl,0b2h ;Desired rights byte
  414. int 31h ;Call DPMI
  415. ;Return arena segment pointer in BX
  416. STA_End:
  417. cEnd
  418. ; NextLRU286
  419. ;
  420. ; Checks the given arena table pointer to see if it is the last
  421. ; arena entry on the list.
  422. ; Uses a grungy method that is necessitated because of the
  423. ; unterminated linked lists we're dealing with here. The count
  424. ; stored is the only reliable method for finding the end. So, to
  425. ; provide random access to blocks in the heap, the heap is searched
  426. ; from top to bottom to find the block and see if it is the last
  427. ; one. If it is or if it is not on the given list, returns a 0
  428. ; pointer to the next item.
  429. ;
  430. ; If this search is for the entire global heap, we do not get the
  431. ; LRU link, but return NULL in AX. This speeds this up alot!
  432. ;
  433. ; Caller: AX = Arena table pointer
  434. ; CX = GLOBAL_ALL, GLOBAL_FREE, or GLOBAL_LRU
  435. ; Return: AX = Next arena table pointer or 0 if no more
  436. ; Trashes all registers except segment registers and SI,DI
  437. cProc NextLRU286, <NEAR,PUBLIC>, <es,ds,si,di>
  438. cBegin
  439. ;** Decode the flags
  440. mov bx,_DATA ;Get the static data segment
  441. mov ds,bx ;Point with DS
  442. mov es,hMaster ;Segment of master block
  443. cmp cx,GLOBAL_ALL ;Don't do this on full heap search
  444. jne @F
  445. jmp SHORT NL_BadList ;Just return NULL for this one
  446. @@: cmp cx,GLOBAL_FREE ;Check free list?
  447. je NL_Free ;Yes
  448. ;** Loop through LRU list until we find this item
  449. NL_LRU:
  450. mov si,ax ;Save the selector in AX
  451. mov cx,es:[gi_lrucount] ;Get the number of objects
  452. jcxz NL_Bad ;No object so return end
  453. dec cx ;We don't want to find the last one
  454. jcxz NL_Bad ;1 object so return end
  455. mov ds,es:[gi_lruchain] ;Get a pointer to the first item
  456. NL_LRULoop:
  457. mov ax,ds ;Get in AX so we can compare
  458. cmp si,ax ;Match yet?
  459. je NL_ReturnNext ;Found it, return next item
  460. mov ds,ds:[ga_lrunext] ;Not found yet, get the next one
  461. loop NL_LRULoop ;Loop through all items
  462. ;** Unlock the LRU sweeping
  463. NL_Bad: dec es:[gi_lrulock] ;OK to LRU sweep now
  464. mov ax, _DATA ;Point to TH Data seg
  465. mov ds, ax
  466. dec wLRUCount ;Keep a count of this
  467. jmp SHORT NL_BadList ;Not here either. Get out
  468. ;** Loop through free list until we find this item
  469. NL_Free:
  470. mov si,ax ;Save the selector in SI
  471. mov cx,es:[gi_free_count] ;Get the number of objects
  472. jcxz NL_BadList ;0 objects so return end
  473. dec cx ;We don't want to find the last one
  474. jcxz NL_BadList ;1 object so return end
  475. mov ds,es:[hi_first] ;Get a pointer to the first item
  476. NL_FreeLoop:
  477. mov ds,ds:[ga_lrunext] ;Not found yet, get the next one
  478. mov ax,ds ;Get the pointer so we can compare it
  479. cmp ax,si ;Is this the one?
  480. je NL_ReturnNext ;Yes, return it
  481. loop NL_FreeLoop ;Loop through all items
  482. jmp SHORT NL_BadList ;Not here either. Get out
  483. NL_ReturnNext:
  484. mov ax,ds:[ga_lrunext] ;Return the next one
  485. jmp SHORT NL_End ;Get out
  486. NL_BadList:
  487. xor ax,ax ;Return zero for error
  488. NL_End:
  489. cEnd
  490. sEnd
  491. END