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.

608 lines
27 KiB

  1. PAGE 60,150
  2. ;***************************************************************************
  3. ;* MEMORY.ASM
  4. ;*
  5. ;* Routines used to handle the read/write random memory API
  6. ;*
  7. ;***************************************************************************
  8. INCLUDE TOOLPRIV.INC
  9. INCLUDE WINDOWS.INC
  10. ;** Symbols
  11. SI_CRITICAL EQU 1
  12. DI_CRITICAL EQU 2
  13. ;** Imports
  14. externA __AHINCR
  15. externFP GlobalEntryHandle
  16. externNP HelperHandleToSel
  17. sBegin CODE
  18. assumes CS,CODE
  19. assumes DS,DATA
  20. ; MemoryRead
  21. ; Uses the passed in selector and offset to read memory into a user-
  22. ; specified buffer. This works for >64K segments and, if code, may
  23. ; have been discarded.
  24. ;
  25. ; This function is normally used for heap selectors. However, if
  26. ; a non-global heap selector is used, it must be less than 64K on
  27. ; a 286.
  28. ;
  29. ; Prototype:
  30. ; DWORD MemoryRead(
  31. ; WORD wSel, /* Selector to read from */
  32. ; DWORD dwOffset, /* Offset to read at */
  33. ; LPSTR lpBuffer, /* Buffer to put data into */
  34. ; DWORD dwcb) /* Number of characters to read */
  35. ; Returns number of characters read (ends at segment limit)
  36. cProc MemoryRead, <FAR,PUBLIC>, <si,di,ds>
  37. parmW wSelector
  38. parmD dwOffset
  39. parmD lpBuffer
  40. parmD dwcb
  41. localD dwcbCopied
  42. localV Global,<SIZE GLOBALENTRY>
  43. cBegin
  44. ;** Make sure the segment is present. We only will fault the
  45. ;** segment in if it is a code segment
  46. cCall HelperHandleToSel, <wSelector> ;Convert to sel from handle
  47. mov wSelector, ax ;Save it so we have a good sel
  48. mov cx, ax
  49. push WORD PTR lpBuffer[2] ;Convert handle to selector
  50. cCall HelperHandleToSel
  51. mov WORD PTR lpBuffer[2], ax ;Save converted handle
  52. lar ax,cx ;Get the access rights
  53. jnz MR_ShortBad ;Failed. It's bad
  54. test ax,8000h ;Is it present?
  55. jnz MR_Present ;Yes
  56. test ax,0800h ;This bit set for code segments
  57. jnz MR_FaultIn ;Code segment, fault it in
  58. MR_ShortBad:
  59. jmp MR_Bad ;Return error
  60. MR_FaultIn:
  61. mov es,wSelector ;Get the selector in ES.
  62. mov al,es:[0] ;Must be at least one byte long
  63. MR_Present:
  64. ;** Check this block's length. We use the global heap functions
  65. ;* to do this because they check in the arena for the length.
  66. ;* This is the only way to get lengths of 286 heap blocks
  67. ;** beyond 64K.
  68. mov ax,SIZE GLOBALENTRY ;Get the size of the structure
  69. mov WORD PTR Global.ge_dwSize[0],ax ;Save in the structure
  70. mov WORD PTR Global.ge_dwSize[2],0 ;Clear the HIWORD
  71. lea ax,Global ;Point to the structure
  72. cCall GlobalEntryHandle, <ss,ax,wSelector>
  73. or ax,ax ;Was this a valid selector?
  74. jnz MR_HeapSel ;Yes, this is a heap selector
  75. ;** If this wasn't a heap selector, we get the length with an LSL.
  76. ;** When used like this, 64K is the max on a 286
  77. MR_NonHeap:
  78. mov bx,wSelector ;Get the selector
  79. mov ax,__WinFlags ;Get the flags
  80. test ax,WF_CPU286 ;286?
  81. jz MR_32BitSize ;No, do 32 bit size stuff
  82. lsl dx,bx ;Get length in DX
  83. mov WORD PTR Global.ge_dwBlockSize[0],dx ;Put in GLOBALENTRY struct
  84. mov WORD PTR Global.ge_dwBlockSize[2],0
  85. jmp SHORT MR_HeapSel
  86. MR_32BitSize:
  87. .386p
  88. lsl edx,ebx
  89. mov Global.ge_dwBlockSize,edx ;Put in GLOBALENTRY struct for later
  90. .286p
  91. MR_HeapSel:
  92. mov dx,WORD PTR dwOffset[2] ;Get the HIWORD of segment offset
  93. cmp dx,WORD PTR Global.ge_dwBlockSize[2] ;Check HIWORD of size
  94. jb MR_OK ;Offset should be OK
  95. je @F ;Equal. Must check LOWORD
  96. jmp MR_Bad ;Offset is not inside segment
  97. @@: mov ax,WORD PTR dwOffset[0] ;Get the LOWORD of segment offset
  98. cmp ax,WORD PTR Global.ge_dwBlockSize[0] ;Check LOWORD of size
  99. jb MR_OK ;It's inside segment
  100. jmp MR_Bad ;Not inside segment
  101. MR_OK:
  102. ;** Do different stuff on 286 and 386/486
  103. mov ax,__WinFlags ;Get the flags
  104. test ax,WF_CPU286 ;286?
  105. jnz MR_Do16Bit ;Yes, do 16 bit stuff
  106. ;** Do this the 386 way (easy)
  107. .386p
  108. mov ax,wSelector ;Point with DS
  109. mov ds,ax ; (keep copy in AX)
  110. mov esi,dwOffset ;Point into the big segment
  111. mov ecx,dwcb ;Get the copy length
  112. lsl edx,eax ;Get the segment limit
  113. sub edx,esi ;Get distance from offset to limit
  114. inc edx ;Make this the real length
  115. cmp ecx,edx ;Are we within the limit?
  116. jbe SHORT MR_LimitOK ;Yes
  117. mov ecx,edx ;No, so make this the copy amount
  118. MR_LimitOK:
  119. mov edx,ecx ;Get the # of bytes to read for ret
  120. xor edi,edi ;Clear the high word
  121. les di,lpBuffer ;Point to the dest. buffer
  122. mov ax,cx ;Save the low bits of ECX
  123. shr ecx,2 ;Prepare for DWORD move
  124. jecxz @F ;No zero-length DWORD moves!
  125. rep movs DWORD PTR [edi],DWORD PTR [esi]
  126. db 67h ;Handles 386 bug
  127. db 90h
  128. @@: mov cx,ax ;Get a copy
  129. jecxz @F ;Don't do zero!
  130. and cx,03 ;Do the remaining 3,2, or 1
  131. rep movs BYTE PTR [edi], BYTE PTR [esi]
  132. db 67h ;Handles 386 bug
  133. db 90h
  134. @@: mov ax,dx ;Bytes copied returned in DX:AX
  135. shr edx,16
  136. jmp MR_End ;Get out
  137. .286p
  138. ;** Do this the 286 way (hard)
  139. MR_Do16Bit:
  140. ;** Compute the actual copy length
  141. mov ax,WORD PTR Global.ge_dwBlockSize[0] ;Get the segment size
  142. mov dx,WORD PTR Global.ge_dwBlockSize[2]
  143. sub ax,WORD PTR dwOffset[0] ;Get distance from offset to limit
  144. sbb dx,WORD PTR dwOffset[2]
  145. cmp dx,WORD PTR dwcb[2] ;Off end of heap block?
  146. ja MR_LimOk ;No, just do it
  147. jb MR_Truncate ;Yes, must truncate our length
  148. cmp ax,WORD PTR dwcb[0] ;Are we off the end?
  149. jae MR_LimOk ;No, just do it
  150. MR_Truncate:
  151. mov WORD PTR dwcb[0],ax ;Force this to be the new length
  152. mov WORD PTR dwcb[2],dx
  153. MR_LimOk:
  154. ;** Save the number of bytes to be copied for the return value
  155. mov ax,WORD PTR dwcb[0] ;Get the LOWORD
  156. mov WORD PTR dwcbCopied[0],ax ;Save it
  157. mov ax,WORD PTR dwcb[2] ;Get the HIWORD
  158. mov WORD PTR dwcbCopied[2],ax ;Save it
  159. ;** Position the initial copying selectors
  160. mov al,BYTE PTR dwOffset[2] ;Grab the HIWORD (286 is only 24 bits)
  161. mov ah,__AHINCR ;Get the selector inc value
  162. mul ah ;Multiply to get sel offset
  163. add ax,wSelector ;AX = sel in sel array
  164. mov ds,ax ;Point to this with DS
  165. mov si,WORD PTR dwOffset[0] ;Get the current pointers
  166. les di,lpBuffer
  167. ;** This is the main copying loop
  168. MR_CopyLoop:
  169. ;** Compute the size of this block copy. This is done by finding the
  170. ;* smaller of the following quantities:
  171. ;* - Distance to end of source segment
  172. ;* - Distance to end of dest. segment
  173. ;** - Distance to end of copy
  174. xor bx,bx ;Flags start at zero
  175. xor cx,cx ;Get the highest segment value (64K)
  176. cmp di,si ;The bigger of the two will win
  177. je MR_Equal ;They're the same
  178. ja MR_DIBigger ;DI is bigger
  179. sub cx,si ;SI bigger, compute dist to end
  180. or bx,SI_CRITICAL ;Flag set for SI-critical
  181. jmp SHORT MR_CheckEndCopy ;Go on
  182. MR_Equal:
  183. sub cx,di ;Use DI (SI and DI are the same)
  184. or bx,SI_CRITICAL OR DI_CRITICAL ;Both will come true
  185. jmp SHORT MR_CheckEndCopy ;Go on
  186. MR_DIBigger:
  187. sub cx,di ;SI is bigger
  188. or bx,DI_CRITICAL ;Flag clear for DI-critical
  189. MR_CheckEndCopy:
  190. cmp WORD PTR dwcb[2],0 ;Check for less than 64K left
  191. ja MR_DoCopy ;Nope. More than 64K left
  192. jcxz MR_GetSize ;CX = 0 is full 64K segment
  193. cmp WORD PTR dwcb[0],cx ;Less than in either segment left?
  194. ja MR_DoCopy ;No. Do it
  195. MR_GetSize:
  196. mov cx,WORD PTR dwcb[0] ;Get in CX
  197. MR_DoCopy:
  198. ;** Do this block of 64K or less.
  199. mov dx,cx ;Save the number of bytes we did
  200. jcxz @F ;Do 64K
  201. shr cx,1 ;Do WORDS
  202. jmp SHORT MR_10 ;Skip over
  203. @@: mov cx,8000h ;32K WORDS
  204. MR_10: jcxz @F ;No zero length WORD moves!
  205. rep movsw ;Do the copy
  206. @@: mov cx,dx ;Get any remaining bits
  207. and cx,1 ;Any more to do?
  208. jcxz @F ;No, don't do it
  209. movsb ;Do the odd byte if necessary
  210. @@: mov cx,dx ;Get back in CX
  211. ;** Bump the loop pointers
  212. jcxz MR_BigCount ;We did 64K
  213. sub WORD PTR dwcb[0],cx ;Subtract the bytes done
  214. sbb WORD PTR dwcb[2],0 ; and don't forget the HIWORD
  215. jmp SHORT MR_20 ;Continue
  216. MR_BigCount:
  217. sub WORD PTR dwcb[2],1 ;Subtract 64K
  218. MR_20: mov ax,WORD PTR dwcb[0] ;We're done if the count of bytes
  219. or ax,WORD PTR dwcb[2] ; is zero
  220. jnz @F ;Not zero, go on
  221. mov dx,WORD PTR dwcbCopied[2] ;Get the return count
  222. mov ax,WORD PTR dwcbCopied[0]
  223. jmp SHORT MR_End ;Get out
  224. @@: test bx,SI_CRITICAL ;Does SI need incrementing?
  225. jz MR_TestDI ;No, try DI
  226. mov ax,ds ;Get the segment value
  227. add ax,__AHINCR ;Bump to next selector
  228. mov ds,ax ;Point with DS still
  229. xor si,si ;Point to start of this segment
  230. MR_TestDI:
  231. test bx,DI_CRITICAL ;Does SI need incrementing?
  232. jz MR_Continue ;No, try DI
  233. mov ax,es ;Get the segment value
  234. add ax,__AHINCR ;Bump to next selector
  235. mov es,ax ;Point with DS still
  236. xor di,di ;Point to start of this segment
  237. MR_Continue:
  238. jmp MR_CopyLoop ;Do it again
  239. MR_Bad:
  240. xor ax,ax ;Return DWORD 0
  241. cwd
  242. MR_End:
  243. cEnd
  244. ; MemoryWrite
  245. ; Uses the passed in selector and offset to write memory from a user-
  246. ; specified buffer. This works for >64K segments and, if code, may
  247. ; have been discarded. The selector may be a selector or a handle
  248. ; but MUST be on the global heap (no aliases or selector array
  249. ; members). If worried about low memory conditions, lpBuffer should
  250. ; be in a (temporarily) fixed segment.
  251. ;
  252. ; Prototype:
  253. ; DWORD MemoryWrite(
  254. ; WORD wSel, /* Selector to read from */
  255. ; DWORD dwOffset, /* Offset to read at */
  256. ; LPSTR lpBuffer, /* Buffer to put data into */
  257. ; DWORD dwcb) /* Number of characters to read */
  258. ; Returns number of characters read (ends at segment limit)
  259. cProc MemoryWrite, <FAR,PUBLIC>, <si,di,ds>
  260. parmW wSelector
  261. parmD dwOffset
  262. parmD lpBuffer
  263. parmD dwcb
  264. localW wSelFlag
  265. localD dwcbCopied
  266. localV DPMISelBuf,8
  267. localV Global,<SIZE GLOBALENTRY>
  268. cBegin
  269. ;** Make sure the segment is present. We only will fault the
  270. ;** segment in if it is a code segment
  271. cCall HelperHandleToSel, <wSelector> ;Convert to sel from handle
  272. mov wSelector, ax ;Save it
  273. mov cx,ax ;Get the selector
  274. push WORD PTR lpBuffer[2] ;Convert handle to selector
  275. cCall HelperHandleToSel
  276. mov WORD PTR lpBuffer[2], ax ;Save converted handle
  277. mov wSelFlag,0 ;Clear the flag
  278. lar ax,cx ;Get the access rights
  279. jnz MW_ShortBad ;Failed
  280. test ax,8000h ;Is it present?
  281. jnz MW_Present ;Yes
  282. test ax,0800h ;This bit set for code segments
  283. jnz MW_FaultIn ;Code segment, fault it in
  284. MW_ShortBad:
  285. jmp MW_Bad ;Return error
  286. MW_FaultIn:
  287. mov es,wSelector ;Get the selector in ES.
  288. mov al,es:[0] ;Must be at least one byte long
  289. MW_Present:
  290. ;** Check this block's length. We use the global heap functions
  291. ;* to do this because they check in the arena for the length.
  292. ;* This is the only way to get lengths of 286 heap blocks
  293. ;** beyond 64K.
  294. mov ax,SIZE GLOBALENTRY ;Get the size of the structure
  295. mov WORD PTR Global.ge_dwSize[0],ax ;Save in the structure
  296. mov WORD PTR Global.ge_dwSize[2],0 ;Clear the HIWORD
  297. lea ax,Global ;Point to the structure
  298. cCall GlobalEntryHandle, <ss,ax,wSelector>
  299. or ax,ax ;Was this a valid selector?
  300. jnz MW_HeapSel ;Yes, this is a heap selector
  301. ;** If this wasn't a heap selector, we get the length with an LSL.
  302. ;** When used like this, 64K is the max on a 286
  303. MW_NonHeap:
  304. mov bx,wSelector ;Get the selector
  305. mov ax,__WinFlags ;Get the flags
  306. test ax,WF_CPU286 ;286?
  307. jz MW_32BitSize ;No, do 32 bit size stuff
  308. lsl dx,bx ;Get length in DX
  309. mov WORD PTR Global.ge_dwBlockSize[0],dx ;Put in GLOBALENTRY struct
  310. mov WORD PTR Global.ge_dwBlockSize[2],0
  311. jmp SHORT MW_HeapSel
  312. MW_32BitSize:
  313. .386p
  314. lsl edx,ebx
  315. mov Global.ge_dwBlockSize,edx ;Put in GLOBALENTRY struct for later
  316. .286p
  317. MW_HeapSel:
  318. mov dx,WORD PTR dwOffset[2] ;Get the HIWORD of segment offset
  319. cmp dx,WORD PTR Global.ge_dwBlockSize[2] ;Check HIWORD of size
  320. jb MW_OK ;Offset should be OK
  321. je @F ;Equal. Must check LOWORD
  322. jmp MW_Bad ;Offset is not inside segment
  323. @@: mov ax,WORD PTR dwOffset[0] ;Get the LOWORD of segment offset
  324. cmp ax,WORD PTR Global.ge_dwBlockSize[0] ;Check LOWORD of size
  325. jb MW_OK ;It's inside segment
  326. jmp MW_Bad ;Not inside segment
  327. MW_OK:
  328. ;** Do different stuff on 286 and 386/486
  329. mov ax,__WinFlags ;Get the flags
  330. test ax,WF_CPU286 ;286?
  331. jnz MW_Do16Bit ;Yes, do 16 bit stuff
  332. ;** Do this the 386 way (easy)
  333. .386p
  334. ;** Get an alias selector if necessary
  335. mov ax,wSelector ;Get the source selector
  336. push ss ;Get ES = SS
  337. pop es
  338. lea di,DPMISelBuf ;Point to our descriptor buffer
  339. cCall MakeAlias ;Make the alias selector
  340. jnc SHORT @F ;No error
  341. jmp MW_Bad ;Must be error
  342. @@: mov wSelFlag,bx ;Set the selector flag
  343. mov wSelector,ax ;Save the new selector
  344. ;** Do the copying
  345. mov ax,wSelector ;Point with DS
  346. mov es,ax ; (keep copy in AX)
  347. mov edi,dwOffset ;Point into the big segment
  348. mov ecx,dwcb ;Get the copy length
  349. lsl edx,eax ;Get the segment limit
  350. sub edx,edi ;Get distance from offset to limit
  351. inc edx ;Make this the real length
  352. cmp ecx,edx ;Are we within the limit?
  353. jbe SHORT MW_LimitOK ;Yes
  354. mov ecx,edx ;No, so make this the copy amount
  355. MW_LimitOK:
  356. xor esi,esi ;Clear the high word
  357. lds si,lpBuffer ;Point to the dest. buffer
  358. mov eax,ecx ;Save ECX
  359. shr ecx,2 ;Prepare for DWORD move
  360. jecxz @F ;No zero-length DWORD moves!
  361. rep movs DWORD PTR [edi],DWORD PTR [esi]
  362. db 67h ;Handles 386 bug
  363. db 90h
  364. @@: mov ecx,eax ;Get a copy
  365. jecxz @F ;Don't do zero!
  366. and ecx,03 ;Do the remaining 3,2, or 1
  367. rep movs BYTE PTR [edi], BYTE PTR [esi]
  368. db 67h ;Handles 386 bug
  369. db 90h
  370. @@: mov edx,eax ;Bytes copied returned in DX:AX
  371. shr edx,16
  372. ;** Free alias if necessary
  373. push ax ;Save return value
  374. push dx
  375. cmp wSelFlag,0 ;Selector flag set?
  376. je SHORT @F ;Nope
  377. mov ax,1 ;DPMI function - Free Selector
  378. mov bx,wSelector ;Selector to free
  379. int 31h ;Call DPMI
  380. @@: pop dx
  381. pop ax
  382. jmp MW_End ;Get out
  383. .286p
  384. ;** Do this the 286 way (hard)
  385. MW_Do16Bit:
  386. ;** Compute the actual copy length
  387. mov ax,WORD PTR Global.ge_dwBlockSize[0] ;Get the segment size
  388. mov dx,WORD PTR Global.ge_dwBlockSize[2]
  389. sub ax,WORD PTR dwOffset[0] ;Get distance from offset to limit
  390. sbb dx,WORD PTR dwOffset[2]
  391. cmp dx,WORD PTR dwcb[2] ;Off end of heap block?
  392. ja MW_LimOk ;No, just do it
  393. jb MW_Truncate ;Yes, must truncate our length
  394. cmp ax,WORD PTR dwcb[0] ;Are we off the end?
  395. jae MW_LimOk ;No, just do it
  396. MW_Truncate:
  397. mov WORD PTR dwcb[0],ax ;Force this to be the new length
  398. mov WORD PTR dwcb[2],dx
  399. MW_LimOk:
  400. ;** Save the number of bytes to be copied for the return value
  401. mov ax,WORD PTR dwcb[0] ;Get the LOWORD
  402. mov WORD PTR dwcbCopied[0],ax ;Save it
  403. mov ax,WORD PTR dwcb[2] ;Get the HIWORD
  404. mov WORD PTR dwcbCopied[2],ax ;Save it
  405. ;** Position the initial copying selectors
  406. mov al,BYTE PTR dwOffset[2] ;Grab the HIWORD (286 is only 24 bits)
  407. mov ah,__AHINCR ;Get the selector inc value
  408. mul ah ;Multiply to get sel offset
  409. add ax,wSelector ;AX = sel in sel array
  410. mov es,ax ;Point to this with DS
  411. mov di,WORD PTR dwOffset[0] ;Get the current pointers
  412. lds si,lpBuffer
  413. ;** This is the main copying loop
  414. MW_CopyLoop:
  415. ;** Get an alias selector if necessary
  416. push si ;Save regs
  417. push di
  418. mov ax,es ;Get the source selector
  419. push ss ;Get ES = SS
  420. pop es
  421. lea di,DPMISelBuf ;Point to our descriptor buffer
  422. cCall MakeAlias ;Make the alias selector
  423. pop di ;Restore regs
  424. pop si
  425. jnc @F ;No error
  426. jmp MW_Bad ;Must be error
  427. @@: mov wSelFlag,bx ;Set the selector flag
  428. mov es,ax ;Save the new selector
  429. ;** Compute the size of this block copy. This is done by finding the
  430. ;* smaller of the following quantities:
  431. ;* - Distance to end of source segment
  432. ;* - Distance to end of dest. segment
  433. ;** - Distance to end of copy
  434. xor bx,bx ;Flags start at zero
  435. xor cx,cx ;Get the highest segment value (64K)
  436. cmp di,si ;The bigger of the two will win
  437. je MW_Equal ;They're the same
  438. ja MW_DIBigger ;DI is bigger
  439. sub cx,si ;SI bigger, compute dist to end
  440. or bx,SI_CRITICAL ;Flag set for SI-critical
  441. jmp SHORT MW_CheckEndCopy ;Go on
  442. MW_Equal:
  443. sub cx,di ;Use DI (SI and DI are the same)
  444. or bx,SI_CRITICAL OR DI_CRITICAL ;Both will come true
  445. jmp SHORT MW_CheckEndCopy ;Go on
  446. MW_DIBigger:
  447. sub cx,di ;SI is bigger
  448. or bx,DI_CRITICAL ;Flag clear for DI-critical
  449. MW_CheckEndCopy:
  450. cmp WORD PTR dwcb[2],0 ;Check for less than 64K left
  451. ja MW_DoCopy ;Nope. More than 64K left
  452. jcxz MW_GetSize ;CX = 0 is full 64K segment
  453. cmp WORD PTR dwcb[0],cx ;Less than in either segment left?
  454. ja MW_DoCopy ;No. Do it
  455. MW_GetSize:
  456. mov cx,WORD PTR dwcb[0] ;Get in CX
  457. MW_DoCopy:
  458. ;** Do this block of 64K or less.
  459. mov dx,cx ;Save the number of bytes we did
  460. jcxz @F ;Do 64K
  461. shr cx,1 ;Do WORDS
  462. jmp SHORT MW_10 ;Skip over
  463. @@: mov cx,8000h ;32K WORDS
  464. MW_10: jcxz @F ;No zero-length WORD moves
  465. rep movsw ;Do the copy
  466. @@: mov cx,dx ;Get any remaining bits
  467. and cx,1 ;Any more to do?
  468. jcxz @F ;No, don't do it
  469. movsb ;Do the odd byte if necessary
  470. @@: mov cx,dx ;Get back in CX
  471. ;** Bump the loop pointers
  472. jcxz MW_BigCount ;We did 64K
  473. sub WORD PTR dwcb[0],cx ;Subtract the bytes done
  474. sbb WORD PTR dwcb[2],0 ; and don't forget the HIWORD
  475. jmp SHORT MW_20 ;Continue
  476. MW_BigCount:
  477. sub WORD PTR dwcb[2],1 ;Subtract 64K
  478. MW_20: mov ax,WORD PTR dwcb[0] ;We're done if the count of bytes
  479. or ax,WORD PTR dwcb[2] ; is zero
  480. jnz @F ;Not zero, go on
  481. mov dx,WORD PTR dwcbCopied[2] ;Get the return count
  482. mov ax,WORD PTR dwcbCopied[0]
  483. jmp SHORT MW_End ;Get out
  484. @@: test bx,SI_CRITICAL ;Does SI need incrementing?
  485. jz MW_TestDI ;No, try DI
  486. mov ax,ds ;Get the segment value
  487. add ax,__AHINCR ;Bump to next selector
  488. mov ds,ax ;Point with DS still
  489. xor si,si ;Point to start of this segment
  490. MW_TestDI:
  491. test bx,DI_CRITICAL ;Does SI need incrementing?
  492. jz MW_Continue ;No, try DI
  493. mov ax,es ;Get the segment value
  494. add ax,__AHINCR ;Bump to next selector
  495. mov es,ax ;Point with DS still
  496. xor di,di ;Point to start of this segment
  497. MW_Continue:
  498. ;** Free alias if necessary
  499. cmp wSelFlag,0 ;Selector flag set?
  500. je @F ;Nope
  501. mov ax,1 ;DPMI function - Free Selector
  502. mov bx,wSelector ;Selector to free
  503. int 31h ;Call DPMI
  504. @@: jmp MW_CopyLoop ;Do it again
  505. MW_Bad:
  506. xor ax,ax ;Return DWORD 0
  507. cwd
  508. MW_End:
  509. cEnd
  510. ;** Helper functions
  511. ; MakeAlias
  512. ; Makes an alias selector for the selector in AX. The new selector
  513. ; is returned in AX. Carry is set on exit if error.
  514. ; Returns nonzero in BX if an alias was made, zero if not
  515. ; ES:DI points to an 8-byte descriptor buffer
  516. cProc MakeAlias, <NEAR, PUBLIC>, <si,di>
  517. cBegin
  518. ;** If this is not a read/write selector, we must create an alias.
  519. ;* In order to be able to free up the selector, we set a flag
  520. ;** so we know to free it.
  521. xor si,si ;No alias made, just in case
  522. lar cx,ax ;Get its access rights
  523. jnz MA_Bad ;Failed
  524. test cx,800h ;Is this a code segment?
  525. jnz MA_MakeAlias ;Yes. Always make an alias
  526. test cx,200h ;Is it read/write?
  527. jnz MA_End ;Yes, no need for alias
  528. MA_MakeAlias:
  529. mov bx,ax ;Get the selector
  530. mov ax,0bh ;DPMI function - Get Descriptor
  531. ;ES:DI already point to buffer
  532. int 31h ;Call DPMI
  533. jc MA_Bad ;Error
  534. xor ax,ax ;DPMI Function - Alloc selector
  535. mov cx,1 ;Alloc 1 selector
  536. int 31h ;Call DPMI
  537. jc MA_Bad ;Error
  538. mov si,1 ;Set flag to say alias made
  539. and BYTE PTR DPMISelBuf[5],0f0h ;Mask out unwanted bits
  540. or BYTE PTR DPMISelBuf[5],2 ;Make it a R/W Data segment
  541. mov bx,ax ;Selector in BX
  542. mov ax,0ch ;DPMI function - Set Descriptor
  543. int 31h ;Call DPMI
  544. jc MA_Bad ;Error
  545. mov ax,bx ;Get the new selector in AX
  546. jmp SHORT MA_End ;Get out
  547. MA_Bad:
  548. stc ;Error
  549. MA_End:
  550. mov bx,si ;Get flag in BX
  551. cEnd
  552. sEnd
  553. END