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.

425 lines
8.1 KiB

  1. ; mem.asm:
  2. ;
  3. ; masm -Mx -Zi -DSEGNAME=????? asm.asm
  4. ;
  5. TITLE MEM.ASM
  6. ;****************************************************************
  7. ;* MEM.ASM - Assembly mem-copy routines *
  8. ;* for 80286 and 80386 *
  9. ;****************************************************************
  10. ;
  11. ?PLM=1 ; PASCAL Calling convention is DEFAULT
  12. ?WIN=0 ; Windows calling convention
  13. PMODE=1
  14. .xlist
  15. include cmacros.inc
  16. include windows.inc
  17. .list
  18. externA __WinFlags ; in KERNEL
  19. externA __AHINCR ; in KERNEL
  20. externA __AHSHIFT ; in KERNEL
  21. ; The following structure should be used to access high and low
  22. ; words of a DWORD. This means that "word ptr foo[2]" -> "foo.hi".
  23. LONG struc
  24. lo dw ?
  25. hi dw ?
  26. LONG ends
  27. FARPOINTER struc
  28. off dw ?
  29. sel dw ?
  30. FARPOINTER ends
  31. ; Manually perform "push" dword register instruction to remove warning
  32. PUSHD macro reg
  33. db 66h
  34. push reg
  35. endm
  36. ; Manually perform "pop" dword register instruction to remove warning
  37. POPD macro reg
  38. db 66h
  39. pop reg
  40. endm
  41. ; -------------------------------------------------------
  42. ; DATA SEGMENT DECLARATIONS
  43. ; -------------------------------------------------------
  44. ifndef SEGNAME
  45. SEGNAME equ <_TEXT>
  46. endif
  47. createSeg %SEGNAME, CodeSeg, word, public, CODE
  48. sBegin Data
  49. sEnd Data
  50. sBegin CodeSeg
  51. assumes cs,CodeSeg
  52. assumes ds,DATA
  53. ;---------------------------Public-Routine------------------------------;
  54. ; hmemcpy
  55. ;
  56. ; copy memory
  57. ;
  58. ; Entry:
  59. ; lpSrc HPSTR to copy from
  60. ; lpDst HPSTR to copy to
  61. ; cbMem DWORD count of bytes to move
  62. ;
  63. ; NOTE: overlapped copies will work iff lpSrc.sel == lpDst.sel
  64. ; [This is a lie. They will always work.]
  65. ;
  66. ; Returns:
  67. ; destination pointer
  68. ; Error Returns:
  69. ; None
  70. ; Registers Preserved:
  71. ; BP,DS,SI,DI
  72. ; Registers Destroyed:
  73. ; AX,BX,CX,DX,FLAGS
  74. ; Calls:
  75. ; nothing
  76. ; History:
  77. ;
  78. ; Wed 04-Jan-1990 13:45:58 -by- Todd Laney [ToddLa]
  79. ; Created.
  80. ; Tue 16-Oct-1990 16:41:00 -by- David Maymudes [DavidMay]
  81. ; Modified 286 case to work correctly with cbMem >= 64K.
  82. ; Changed name to hmemcpy.
  83. ; Changed 386 case to copy by longwords
  84. ;-----------------------------------------------------------------------;
  85. cProc MemCopy,<FAR,PASCAL,PUBLIC,NODATA>,<>
  86. ; ParmD lpDst
  87. ; ParmD lpSrc
  88. ; ParmD cbMem
  89. cBegin <nogen>
  90. mov ax,__WinFlags
  91. test ax,WF_CPU286
  92. jz fmemcpy386
  93. jmp FAR PTR fmemcpy286
  94. cEnd <nogen>
  95. cProc fmemcpy386,<FAR,PASCAL,PUBLIC,NODATA>,<ds>
  96. ParmD lpDst
  97. ParmD lpSrc
  98. ParmD cbMem
  99. cBegin
  100. .386
  101. PUSHD di ; push edi
  102. PUSHD si ; push esi
  103. cld
  104. mov ecx,cbMem
  105. jecxz mc386_exit
  106. movzx edi,di
  107. movzx esi,si
  108. lds si,lpSrc
  109. les di,lpDst
  110. ;
  111. ; calculate differance of pointers in "selector" space
  112. ;
  113. mov ax,si ; DX:AX = lpSrc
  114. mov dx,ds
  115. mov bx,es ; BX = selector of ptr B
  116. mov cx,__AHSHIFT ; number of selector bits per 64K 'segment'
  117. shr dx,cl ; linearize ptr A
  118. shr bx,cl ; linearize ptr B
  119. ;
  120. ; DX and BX contain normalized selectors
  121. ;
  122. mov ecx,cbMem
  123. sub ax,di
  124. sbb dx,bx ; do long subtraction.
  125. jnc short mc_copy_forward
  126. add ax,cx
  127. adc dx,cbMem.hi
  128. jnc short mc_copy_forward ; carry, so >0, thus they do hit.
  129. std
  130. add edi,ecx
  131. add esi,ecx
  132. sub edi,4
  133. sub esi,4
  134. PUSHD cx ; push ecx
  135. shr ecx,2 ; get count in DWORDs
  136. rep movs dword ptr es:[edi], dword ptr ds:[esi]
  137. db 67H ; Fix strange 386 bug
  138. add edi,3
  139. add esi,3
  140. POPD cx ; pop ecx
  141. and ecx,3
  142. rep movs byte ptr es:[edi], byte ptr ds:[esi]
  143. db 67H ; Fix strange 386 bug
  144. jmp short mc386_exit
  145. mc_copy_forward:
  146. PUSHD cx ; push ecx
  147. shr ecx,2 ; get count in DWORDs
  148. rep movs dword ptr es:[edi], dword ptr ds:[esi]
  149. db 67H
  150. POPD cx ; pop ecx
  151. and ecx,3
  152. rep movs byte ptr es:[edi], byte ptr ds:[esi]
  153. db 67H
  154. nop
  155. mc386_exit:
  156. cld
  157. POPD si ; pop esi
  158. POPD di ; pop edi
  159. mov dx,lpDst.sel ; return destination address
  160. mov ax,lpDst.off
  161. .286
  162. cEnd
  163. cProc fmemcpy286,<FAR,PASCAL,PUBLIC,NODATA>,<ds,si,di>
  164. ParmD lpDst
  165. ParmD lpSrc
  166. ParmD cbMem
  167. cBegin
  168. mov cx,cbMem.lo ; CX holds count
  169. or cx,cbMem.hi ; or with high word
  170. jnz @f
  171. jmp empty_copy
  172. @@:
  173. lds si,lpSrc ; DS:SI = src
  174. les di,lpDst ; ES:DI = dst
  175. ;
  176. ; calculate differance of pointers in "selector" space
  177. ;
  178. mov ax,si ; DX:AX = lpSrc
  179. mov dx,ds
  180. mov bx,es ; BX = selector of ptr B
  181. mov cx,__AHSHIFT ; number of selector bits per 64K 'segment'
  182. shr dx,cl ; linearize ptr A
  183. shr bx,cl ; linearize ptr B
  184. ;
  185. ; DX and BX contain normalized selectors
  186. ;
  187. mov cx,cbMem.lo
  188. sub ax,di
  189. sbb dx,bx ; do long subtraction.
  190. jnc forward_copy ; difference is positive, so copy forward
  191. ; see if the blocks intersect: is source + count > dest?
  192. ; equivalently, is source-dest + count > 0 ?
  193. ; sub ax,cx
  194. ; sbb dx,0
  195. ; jnc next ; This looks wrong. Recheck!
  196. add ax,cx
  197. adc dx,cbMem.hi
  198. jc reverse_copy ; carry, so >0, thus they do hit.
  199. forward_copy:
  200. jmp next
  201. reverse_copy:
  202. ; first, we have to set ds:si and es:di to the _ends_ of the blocks
  203. sub cx,1
  204. sbb cbMem.hi,0 ; subtract 2 from (long) count
  205. xor ax,ax
  206. add si,cx
  207. adc ax,cbMem.hi
  208. push cx
  209. mov cx,__AHSHIFT
  210. shl ax,cl
  211. pop cx
  212. mov bx,ds
  213. add ax,bx ; advance DS
  214. mov ds,ax
  215. xor ax,ax
  216. add di,cx
  217. adc ax,cbMem.hi
  218. push cx
  219. mov cx,__AHSHIFT
  220. shl ax,cl
  221. pop cx
  222. mov bx,es
  223. add ax,bx ; advance ES
  224. mov es,ax
  225. add cx,1
  226. adc cbMem.hi,0 ; restore count
  227. ;
  228. ; DS:SI += Count
  229. ; ES:DI += Count
  230. ; While Count != 0 Do
  231. ; Num = MIN(Count,SI+1,DI+1)
  232. ; Reverse Copy "Num" Bytes from DS:SI to ES:DI
  233. ; (SI -= Num, DI -= Num)
  234. ; Count -= Num
  235. ; If Count == 0 Then
  236. ; BREAK
  237. ; If SI == 0xFFFF Then
  238. ; DS -= __AHINCR
  239. ; If DI == 0xFFFF Then
  240. ; ES -= __AHINCR
  241. ;
  242. next_r:
  243. mov ax,si
  244. sub ax,di
  245. sbb bx,bx
  246. and ax,bx
  247. add ax,di ; AX = MIN(SI, DI)
  248. test cbMem.hi,-1 ; is high word not zero?
  249. jnz @f ; at least 64k to go
  250. dec cx
  251. sub ax,cx
  252. sbb bx,bx
  253. and ax,bx
  254. add ax,cx
  255. inc cx
  256. @@:
  257. xor bx,bx
  258. add ax,1 ; AX = Num = MIN(Count-1,SI,DI)+1
  259. adc bx,0 ; bx==1 if exactly 64k
  260. xchg ax,cx
  261. sub ax,cx ; Count -= Num
  262. sbb cbMem.hi,bx
  263. std
  264. shr bx,1
  265. rcr cx,1 ; if bx==1, then cx ends up 0x8000
  266. dec si
  267. dec di
  268. rep movsw
  269. inc si ; realign pointers
  270. inc di
  271. adc cl,cl
  272. rep movsb ; move last byte, if necessary
  273. cld
  274. mov cx,ax ; restore cx
  275. or ax,cbMem.hi
  276. jz done ; If Count == 0 Then BREAK
  277. cmp si,-1 ; if SI wraps, update DS
  278. jne @f
  279. mov ax,ds
  280. sub ax,__AHINCR
  281. mov ds,ax ; update DS if appropriate
  282. @@:
  283. cmp di,-1 ; if DI wraps, update ES
  284. jne next_r
  285. mov ax,es
  286. sub ax,__AHINCR
  287. mov es,ax ; update ES if appropriate
  288. jmp next_r
  289. ;
  290. ; While Count != 0 Do
  291. ; If (Count + SI > 65536) OR (Count + DI > 65536) Then
  292. ; Num = Min(65536-SI, 65536-DI)
  293. ; Else
  294. ; Num = Count
  295. ; Copy "Num" Bytes from DS:SI to ES:DI (SI += Num, DI += Num)
  296. ; Count -= Num
  297. ; If Count == 0 Then
  298. ; BREAK
  299. ; If SI == 0 Then
  300. ; DS += __AHINCR
  301. ; If DI == 0 Then
  302. ; ES += __AHINCR
  303. ;
  304. next:
  305. ;;;;;;;;mov ax,cx
  306. ;;;;;;;;dec ax
  307. mov ax,di
  308. not ax ; AX = 65535-DI
  309. mov dx,si
  310. not dx ; DX = 65535-SI
  311. sub ax,dx
  312. sbb bx,bx
  313. and ax,bx
  314. add ax,dx ; AX = MIN(AX,DX) = MIN(65535-SI,65535-DI)
  315. ; problem: ax might have wrapped to zero
  316. test cbMem.hi,-1
  317. jnz plentytogo ; at least 64k still to copy
  318. dec cx ; this is ok, since high word is zero
  319. sub ax,cx
  320. sbb bx,bx
  321. and ax,bx
  322. add ax,cx ; AX = MIN(AX,CX)
  323. inc cx
  324. plentytogo:
  325. xor bx,bx
  326. add ax,1 ; AX = Num = MIN(count,65536-SI,65536-DI)
  327. ; we must check the carry here!
  328. adc bx,0 ; BX could be 1 here, if CX==0 indicating
  329. ; exactly 64k to copy
  330. xchg ax,cx
  331. sub ax,cx ; Count -= Num
  332. sbb cbMem.hi,bx
  333. shr bx,1
  334. rcr cx,1 ; if bx==1, then cx ends up 0x8000
  335. rep movsw
  336. adc cl,cl
  337. rep movsb ; move last byte, if necessary
  338. mov cx,ax ; put low word of count back in cx
  339. or ax,cbMem.hi
  340. jz done ; If Count == 0 Then BREAK
  341. or si,si ; if SI wraps, update DS
  342. jnz @f
  343. mov ax,ds
  344. add ax,__AHINCR
  345. mov ds,ax ; update DS if appropriate
  346. @@:
  347. or di,di ; if DI wraps, update ES
  348. jnz next
  349. mov ax,es
  350. add ax,__AHINCR
  351. mov es,ax ; update ES if appropriate
  352. jmp next
  353. ;
  354. ; Restore registers and return
  355. ;
  356. done:
  357. empty_copy:
  358. mov dx,lpDst.sel ; return destination address
  359. mov ax,lpDst.off
  360. cEnd
  361. sEnd
  362. sEnd CodeSeg
  363. end