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.

541 lines
22 KiB

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