diff options
| author | 2024-04-25 21:24:10 +0100 | |
|---|---|---|
| committer | 2024-04-25 22:32:27 +0000 | |
| commit | 2d04cacc5322951f187bb17e017c12920ac8ebe2 (patch) | |
| tree | 80ee017efa878dfd5344b44249e6a241f2a7f6e2 /v4.0/src/MEMM/EMM/EMMP.ASM | |
| parent | Merge pull request #430 from jpbaltazar/typoptbr (diff) | |
| download | ms-dos-main.tar.gz ms-dos-main.tar.xz ms-dos-main.zip | |
Diffstat (limited to 'v4.0/src/MEMM/EMM/EMMP.ASM')
| -rw-r--r-- | v4.0/src/MEMM/EMM/EMMP.ASM | 2978 |
1 files changed, 2978 insertions, 0 deletions
diff --git a/v4.0/src/MEMM/EMM/EMMP.ASM b/v4.0/src/MEMM/EMM/EMMP.ASM new file mode 100644 index 0000000..a60b46e --- /dev/null +++ b/v4.0/src/MEMM/EMM/EMMP.ASM | |||
| @@ -0,0 +1,2978 @@ | |||
| 1 | page 58,132 | ||
| 2 | ;****************************************************************************** | ||
| 3 | title EMMP - EMM protected mode functions | ||
| 4 | ;****************************************************************************** | ||
| 5 | ; | ||
| 6 | ; (C) Copyright MICROSOFT Corp. 1986, 1987 | ||
| 7 | ; | ||
| 8 | ; Title: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver | ||
| 9 | ; EMMLIB.LIB - Expanded Memory Manager Functions Library | ||
| 10 | ; | ||
| 11 | ; Module: EMMP - WIN386 EMM functions | ||
| 12 | ; | ||
| 13 | ; Version: 0.04 | ||
| 14 | ; | ||
| 15 | ; Date: July 7,1986 | ||
| 16 | ; | ||
| 17 | ;****************************************************************************** | ||
| 18 | ; | ||
| 19 | ; Change log: | ||
| 20 | ; | ||
| 21 | ; DATE REVISION DESCRIPTION | ||
| 22 | ; -------- -------- ------------------------------------------------------- | ||
| 23 | ; 07/07/86 0.04 Moved here from version 0.04 EMMSUP.ASM | ||
| 24 | ; 07/08/86 0.04 Added Get/Set Page Map (SBP). | ||
| 25 | ; 05/13/88 Change to LIM 4.0 functionality (PC) | ||
| 26 | ; | ||
| 27 | ;****************************************************************************** | ||
| 28 | ; | ||
| 29 | ; Functional Description: | ||
| 30 | ; This file contains the EMM functions which require greatest efficiency. | ||
| 31 | ; | ||
| 32 | ;****************************************************************************** | ||
| 33 | .lfcond ; list false conditionals | ||
| 34 | .386p | ||
| 35 | |||
| 36 | ; include protseg.inc | ||
| 37 | include vdmseg.inc | ||
| 38 | include page.inc | ||
| 39 | ; include vdmm.inc | ||
| 40 | include vm386.inc | ||
| 41 | include vdmsel.inc | ||
| 42 | include emmdef.inc | ||
| 43 | include desc.inc | ||
| 44 | ; include vmdm.inc | ||
| 45 | ; include vpicd.inc | ||
| 46 | ; include vdmmmac.inc | ||
| 47 | |||
| 48 | ;****************************************************************************** | ||
| 49 | ; P U B L I C S | ||
| 50 | ;****************************************************************************** | ||
| 51 | _TEXT segment | ||
| 52 | public _MapHandlePage | ||
| 53 | public _SavePageMap | ||
| 54 | public _RestorePageMap | ||
| 55 | public _GetSetPageMap | ||
| 56 | public _GetSetPartial | ||
| 57 | public _MapHandleArray | ||
| 58 | public _AlterMapAndJump | ||
| 59 | public _AlterMapAndCall | ||
| 60 | ; public TS_VEMMD_MC_Ret | ||
| 61 | public _MoveExchangeMemory | ||
| 62 | public _AlternateMapRegisterSet | ||
| 63 | ; public VEMMD_Set_Map_Region | ||
| 64 | ; public VEMMD_Unset_Map_Region | ||
| 65 | ; public _VMpte_to_EMMpte | ||
| 66 | ; public _Remap_EMM | ||
| 67 | public _Get_Key_Val | ||
| 68 | _TEXT ends | ||
| 69 | |||
| 70 | page | ||
| 71 | ;****************************************************************************** | ||
| 72 | ; E X T E R N A L R E F E R E N C E S | ||
| 73 | ;****************************************************************************** | ||
| 74 | |||
| 75 | _TEXT segment | ||
| 76 | |||
| 77 | extrn _source_addr:near | ||
| 78 | extrn _dest_addr:near | ||
| 79 | |||
| 80 | extrn SetDescInfoResident:near | ||
| 81 | extrn SegOffTo24Resident:near | ||
| 82 | |||
| 83 | extrn ErrHndlr:near | ||
| 84 | |||
| 85 | _TEXT ends | ||
| 86 | |||
| 87 | _DATA SEGMENT | ||
| 88 | |||
| 89 | ;extrn _regp:dword ; pointer to entry stack frame | ||
| 90 | ;extrn VEMMD_pt:dword | ||
| 91 | ;extrn Cur_VM_Handle:dword | ||
| 92 | ;extrn Cur_VMID:dword | ||
| 93 | ;extrn _VM_List:dword | ||
| 94 | ;extrn _MaxEMMSize:dword | ||
| 95 | ;extrn _VEMMD_PgFrame:word | ||
| 96 | ;extrn _VEMMD_Last_Offset:word | ||
| 97 | extrn PF_Base:word | ||
| 98 | extrn _OSEnabled:dword | ||
| 99 | ;extrn NullAvailPTE:dword | ||
| 100 | ;extrn NullUnavailPTE:dword | ||
| 101 | |||
| 102 | extrn _total_pages:word ; total # of EMM pages in system | ||
| 103 | |||
| 104 | ; | ||
| 105 | ; table of offsets into in to the first page table | ||
| 106 | ; for user logical emm page map | ||
| 107 | ; | ||
| 108 | extrn _page_frame_base:dword | ||
| 109 | |||
| 110 | extrn _pft386:word | ||
| 111 | |||
| 112 | extrn _mappable_pages:word ; table of mappable pages | ||
| 113 | extrn _mappable_page_count:word ; how many in the table | ||
| 114 | extrn _page_frame_pages:word ; how many in the page frame | ||
| 115 | extrn _physical_page_count:word ; number of physical pages | ||
| 116 | extrn _VM1_EMM_Pages:word ; pages not in the page frame | ||
| 117 | ;extrn _VM1_EMM_Offset:word ; offset of these in a context | ||
| 118 | extrn _cntxt_pages:byte ; number of pages in a context | ||
| 119 | extrn _cntxt_bytes:byte ; number of bytes in a context | ||
| 120 | |||
| 121 | |||
| 122 | ; | ||
| 123 | ; table of indexes into the above - maps segment to physical page | ||
| 124 | ; | ||
| 125 | extrn EMM_MPindex:byte | ||
| 126 | |||
| 127 | ; | ||
| 128 | ; ptr to table of emm page # for each handle's logical pages. | ||
| 129 | ; | ||
| 130 | extrn _emm_page:word | ||
| 131 | |||
| 132 | ; | ||
| 133 | ; handle data structure | ||
| 134 | ; | ||
| 135 | extrn _handle_table:word | ||
| 136 | extrn _handle_table_size:word | ||
| 137 | |||
| 138 | ; | ||
| 139 | ; save area for handles | ||
| 140 | ; | ||
| 141 | extrn _save_map:byte | ||
| 142 | |||
| 143 | ; | ||
| 144 | ; Save area and misc variables for 4.0 function 27 | ||
| 145 | ; | ||
| 146 | extrn EMM_savES:word | ||
| 147 | extrn EMM_savDI:word | ||
| 148 | |||
| 149 | extrn CurRegSetn:byte | ||
| 150 | extrn FRS_free:byte | ||
| 151 | extrn CurRegSet:dword | ||
| 152 | extrn FRS_array:word | ||
| 153 | |||
| 154 | extrn _regp:word | ||
| 155 | _DATA ENDS | ||
| 156 | |||
| 157 | page | ||
| 158 | ;****************************************************************************** | ||
| 159 | ; C O D E | ||
| 160 | ;****************************************************************************** | ||
| 161 | _TEXT SEGMENT | ||
| 162 | assume cs:_TEXT, ds:DGROUP, ss:DGROUP | ||
| 163 | |||
| 164 | page | ||
| 165 | ;*********************************************** | ||
| 166 | ; | ||
| 167 | ; normalize | ||
| 168 | ; | ||
| 169 | ; ENTRY: Sel,Off - Selector:offset to be normalize | ||
| 170 | ; protected mode only | ||
| 171 | ; | ||
| 172 | ; EXIT: Sel:Off normalized | ||
| 173 | ; | ||
| 174 | ; USES: Sel,Off | ||
| 175 | ; NOTE: Sel and Off should not be BX,DX,AX | ||
| 176 | ; | ||
| 177 | ;*********************************************** | ||
| 178 | normalize MACRO Sel,Off | ||
| 179 | |||
| 180 | push dx | ||
| 181 | push ax | ||
| 182 | push bx | ||
| 183 | push es | ||
| 184 | |||
| 185 | push Sel ; save for later reload | ||
| 186 | mov bx, Sel ; get Selector into BX | ||
| 187 | |||
| 188 | push GDTD_GSEL ; ES -> GDT | ||
| 189 | pop es | ||
| 190 | |||
| 191 | and bl,SEL_LOW_MASK ; mask off mode bits | ||
| 192 | mov dx,es:[bx+2] ; AL:DX <-- base address | ||
| 193 | mov al,es:[bx+4] | ||
| 194 | add dx,Off ; adjust base address | ||
| 195 | adc al,0 | ||
| 196 | mov es:[bx+2],dx ; store it back | ||
| 197 | mov es:[bx+4],al | ||
| 198 | xor Off, Off ; new Offset | ||
| 199 | |||
| 200 | pop Sel ; reload Selector (flush cache) | ||
| 201 | |||
| 202 | pop es | ||
| 203 | pop bx | ||
| 204 | pop ax | ||
| 205 | pop dx | ||
| 206 | |||
| 207 | ENDM | ||
| 208 | |||
| 209 | ;*********************************************** | ||
| 210 | ; | ||
| 211 | ; get_space_from_stack | ||
| 212 | ; | ||
| 213 | ; ENTRY: Len - amount of space requested | ||
| 214 | ; | ||
| 215 | ; EXIT: Len space allocated on ES:DI (client's stack) | ||
| 216 | ; ES:DI - points to First element on top of stack | ||
| 217 | ; | ||
| 218 | ; USES: DI | ||
| 219 | ; | ||
| 220 | ;*********************************************** | ||
| 221 | Get_space_from_stack MACRO Len | ||
| 222 | |||
| 223 | sub di, Len | ||
| 224 | ENDM | ||
| 225 | |||
| 226 | ;*********************************************** | ||
| 227 | ; | ||
| 228 | ; release_space_to_stack | ||
| 229 | ; | ||
| 230 | ; ENTRY: Len - amount of space to be release | ||
| 231 | ; | ||
| 232 | ; EXIT: Len space released from client's stack (DS:SI) | ||
| 233 | ; | ||
| 234 | ; USES: SI | ||
| 235 | ; | ||
| 236 | ;*********************************************** | ||
| 237 | release_space_to_stack MACRO Len | ||
| 238 | |||
| 239 | add si, Len | ||
| 240 | ENDM | ||
| 241 | |||
| 242 | ;*********************************************** | ||
| 243 | ; | ||
| 244 | ; Set_EMM_GDT - set GDT entry of selector with some fix infos | ||
| 245 | ; like access and limit | ||
| 246 | ; | ||
| 247 | ; ENTRY: Handle - selector of GDT to modify | ||
| 248 | ; | ||
| 249 | ; EXIT: GDT entry set | ||
| 250 | ; bx - selector | ||
| 251 | ; | ||
| 252 | ; USES: ax,bx,cx,dx,es | ||
| 253 | ; | ||
| 254 | ;*********************************************** | ||
| 255 | Set_EMM_GDT MACRO handle | ||
| 256 | |||
| 257 | mov bx, handle ; GDT selector | ||
| 258 | call SegOffTo24Resident ; AL:DX <-- 24 bit base address | ||
| 259 | mov cx, 0ffffh ; Limit | ||
| 260 | mov ah, D_DATA0 ; Acess right | ||
| 261 | push GDTD_GSEL | ||
| 262 | pop es ; ES:0 <-- GDT | ||
| 263 | call SetDescInfoResident ; set GDT entry | ||
| 264 | ENDM | ||
| 265 | |||
| 266 | ;*********************************************** | ||
| 267 | ; | ||
| 268 | ; Set_Byte_Gran - set granularity of GDT entry to byte | ||
| 269 | ; | ||
| 270 | ; ENTRY: Handle - selector of GDT to modify | ||
| 271 | ; | ||
| 272 | ; EXIT: Granularity bit clear in GDT | ||
| 273 | ; bx - Selector | ||
| 274 | ; | ||
| 275 | ; USES: bx,es | ||
| 276 | ; | ||
| 277 | ;*********************************************** | ||
| 278 | Set_Byte_Gran MACRO handle | ||
| 279 | |||
| 280 | mov bx, handle ; GDT selector | ||
| 281 | push GDTD_GSEL | ||
| 282 | pop es ; ES:0 <-- GDT | ||
| 283 | and byte ptr es:[bx+6],NOT R_GRAN ; clear gran bit | ||
| 284 | ENDM | ||
| 285 | |||
| 286 | ;*********************************************** | ||
| 287 | ; | ||
| 288 | ; Set_Page_Gran - set granularity of GDT entry to page | ||
| 289 | ; | ||
| 290 | ; ENTRY: Handle - selector of GDT to modify | ||
| 291 | ; | ||
| 292 | ; EXIT: Granularity bit set in GDT | ||
| 293 | ; bx - Selector | ||
| 294 | ; | ||
| 295 | ; USES: bx,es | ||
| 296 | ; | ||
| 297 | ;*********************************************** | ||
| 298 | Set_Page_Gran MACRO handle | ||
| 299 | |||
| 300 | mov bx, handle ; GDT selector | ||
| 301 | push GDTD_GSEL | ||
| 302 | pop es ; ES:0 <-- GDT | ||
| 303 | or byte ptr es:[bx+6], R_GRAN ; set gran bit | ||
| 304 | ENDM | ||
| 305 | |||
| 306 | ;*********************************************** | ||
| 307 | ; | ||
| 308 | ; Get_FRS_window - get pointer to Fast Register Set window | ||
| 309 | ; | ||
| 310 | ; ENTRY: Reg - points to an FRS_struc | ||
| 311 | ; | ||
| 312 | ; EXIT: Reg - points to FRS_window entry in the structure | ||
| 313 | ; | ||
| 314 | ; USES: Reg | ||
| 315 | ; | ||
| 316 | ;*********************************************** | ||
| 317 | Get_FRS_window MACRO Reg | ||
| 318 | |||
| 319 | mov Reg, word ptr [CurRegSet] ; just offset (assume dgroup) | ||
| 320 | add Reg, FRS_window ; points to FRS window entries | ||
| 321 | ENDM | ||
| 322 | |||
| 323 | page | ||
| 324 | ;********************************************************************** | ||
| 325 | ; | ||
| 326 | ; map_EMM_page - set page table entries for a page frame | ||
| 327 | ; | ||
| 328 | ; ENTRY: AX - physical page number to be mapped | ||
| 329 | ; BX - EMM page number to map | ||
| 330 | ; EXIT: page table set up for EMM page # in this page frame | ||
| 331 | ; DESTROY:EAX,BX | ||
| 332 | ; | ||
| 333 | ;*********************************************** | ||
| 334 | map_EMM_page proc near | ||
| 335 | cmp ax,[_physical_page_count] ;Q: valid physical page# ? | ||
| 336 | jae short mEp_inv_page ; N: invalid page number | ||
| 337 | ; Y: continue with it | ||
| 338 | cmp bx,[_total_pages] ;Q: valid EMM page# ? | ||
| 339 | jae short mEp_inv_page ; N: invalid page number | ||
| 340 | ; Y: continue with it | ||
| 341 | push es ; preserve es | ||
| 342 | push cx ; preserve cx | ||
| 343 | push di ; preserve di | ||
| 344 | push ax ; save ax (phys page#) | ||
| 345 | |||
| 346 | ; | ||
| 347 | ; construct pointer to physical address of the first | ||
| 348 | ; 386 page and move it into eax | ||
| 349 | ; | ||
| 350 | mov cx,bx ; emm page# in cx to save in FRS later | ||
| 351 | shl bx,2 ; bx <-- pft index * 4 | ||
| 352 | |||
| 353 | ; | ||
| 354 | ; continue calulation of pte | ||
| 355 | ; | ||
| 356 | add bx,[_pft386] ; BX = points into _pft386 | ||
| 357 | mov eax,[bx] ; EAX = physical address of EMM page # | ||
| 358 | and ax,0F000H ; clear the low 12 bits | ||
| 359 | or ax,P_AVAIL ; page ctl bits <-- user,present,write | ||
| 360 | |||
| 361 | pop bx ; bx <-- physical page index | ||
| 362 | |||
| 363 | ; | ||
| 364 | ; save mapping (offset into _pft386 struct) into | ||
| 365 | ; current FRS's physical page entry | ||
| 366 | ; | ||
| 367 | |||
| 368 | Get_FRS_Window DI ; di <-- address of current FRS | ||
| 369 | add di,bx ; di <-- address of physical page | ||
| 370 | add di,bx ; entry in FRS | ||
| 371 | mov [di],cx ; save mapping (emm page#) into FRS | ||
| 372 | ; | ||
| 373 | ; construct pointer to physical address of | ||
| 374 | ; page frame | ||
| 375 | ; | ||
| 376 | |||
| 377 | shl bx,2 ; bx <-- index * 4 | ||
| 378 | add bx,offset DGROUP:_page_frame_base ; bx = offset for entry in _page_frame_base | ||
| 379 | les di,[bx] ; es:di <-- page frame address | ||
| 380 | |||
| 381 | ; | ||
| 382 | ; now, | ||
| 383 | ; es:di points to the 1st entry in the page table | ||
| 384 | ; for this page frame | ||
| 385 | ; eax contains the new value of the PTE | ||
| 386 | ; set up 4 entries | ||
| 387 | ; | ||
| 388 | |||
| 389 | pushf ; preserve direction flag | ||
| 390 | cld ; forward | ||
| 391 | |||
| 392 | stosd ; store 1st page table entry | ||
| 393 | add eax,P_SIZE ; eax <-- next address | ||
| 394 | |||
| 395 | stosd ; store 2nd page table entry | ||
| 396 | add eax,P_SIZE ; eax <-- next address | ||
| 397 | |||
| 398 | stosd ; store 3rd page table entry | ||
| 399 | add eax,P_SIZE ; eax <-- next address | ||
| 400 | |||
| 401 | stosd ; store 4th page table entry | ||
| 402 | |||
| 403 | popf ; restore direction flag | ||
| 404 | pop di ; get DI back | ||
| 405 | pop cx ; get CX back | ||
| 406 | pop es ; get ES back | ||
| 407 | clc | ||
| 408 | ret | ||
| 409 | |||
| 410 | mEp_inv_page: | ||
| 411 | stc | ||
| 412 | ret | ||
| 413 | |||
| 414 | map_EMM_page endp | ||
| 415 | |||
| 416 | page | ||
| 417 | ;********************************************************************** | ||
| 418 | ; | ||
| 419 | ; unmap_page - unmap a physical page | ||
| 420 | ; | ||
| 421 | ; ENTRY: AX - physical page number to be unmapped | ||
| 422 | ; DESTROY:EAX | ||
| 423 | ; | ||
| 424 | ;********************************************************************** | ||
| 425 | unmap_page proc near | ||
| 426 | ; | ||
| 427 | ; find FRS entry for the physical page and | ||
| 428 | ; update it as unmapped | ||
| 429 | ; | ||
| 430 | push es | ||
| 431 | push di | ||
| 432 | push bx | ||
| 433 | push cx | ||
| 434 | Get_FRS_Window DI ; di <-- address of current FRS | ||
| 435 | add di, ax ; di <-- address of physical page | ||
| 436 | add di, ax ; entry in FRS | ||
| 437 | mov [di], NULL_PAGE ; unmap the entry | ||
| 438 | |||
| 439 | ; | ||
| 440 | ; find out the segment of the physical page | ||
| 441 | ; | ||
| 442 | mov cx, [_physical_page_count] | ||
| 443 | mov di, offset DGROUP:_mappable_pages | ||
| 444 | unmap_page_loop: | ||
| 445 | cmp ax, [di].mappable_pg | ||
| 446 | je unmap_page_found | ||
| 447 | add di, size Mappable_Page | ||
| 448 | loop unmap_page_loop | ||
| 449 | |||
| 450 | jmp short unmap_page_exit ; non-found : just return | ||
| 451 | |||
| 452 | unmap_page_found: | ||
| 453 | mov bx, [di].mappable_seg ; get segment into bx first | ||
| 454 | |||
| 455 | ; | ||
| 456 | ; construct pointer to physical address of | ||
| 457 | ; page frame | ||
| 458 | ; | ||
| 459 | xchg ax,bx | ||
| 460 | shl bx,2 ; bx <-- index * 4 | ||
| 461 | add bx,offset DGROUP:_page_frame_base ; bx <-- points to PTE address of phys page# | ||
| 462 | les di,[bx] ; es:di <-- points to PTE of page frame | ||
| 463 | xchg ax,bx | ||
| 464 | |||
| 465 | ; | ||
| 466 | ; construct PTE | ||
| 467 | ; | ||
| 468 | movzx eax, bx ; EAX <-- segment of physical page | ||
| 469 | shl eax, 4 | ||
| 470 | and ax,0F000H ; clear the low 12 bits | ||
| 471 | or ax,P_AVAIL ; page ctl bits <-- user,present,write | ||
| 472 | |||
| 473 | cmp eax, 0A0000h ; Q:above 640K ? | ||
| 474 | jge unmap_page_ok ; Y: go ahead, unmap it | ||
| 475 | mov eax, 0 ; N: shouldn't unmap below 640K - make page NotPresent | ||
| 476 | |||
| 477 | unmap_page_ok: | ||
| 478 | pushf | ||
| 479 | cld | ||
| 480 | stosd ; unmap pte of page frame | ||
| 481 | add eax,P_SIZE | ||
| 482 | stosd | ||
| 483 | add eax,P_SIZE | ||
| 484 | stosd | ||
| 485 | add eax,P_SIZE | ||
| 486 | stosd | ||
| 487 | popf | ||
| 488 | |||
| 489 | unmap_page_exit: | ||
| 490 | pop cx | ||
| 491 | pop bx | ||
| 492 | pop di | ||
| 493 | pop es | ||
| 494 | ret | ||
| 495 | unmap_page endp | ||
| 496 | |||
| 497 | page | ||
| 498 | ;********************************************************************** | ||
| 499 | ; | ||
| 500 | ; map_page - map a logical page to a phyical page | ||
| 501 | ; | ||
| 502 | ; ENTRY: AX - physical page number to be mapped | ||
| 503 | ; BX - logical page number to map | ||
| 504 | ; DX - handle pointer (do not destroy) | ||
| 505 | ; DESTROY:EAX,BX | ||
| 506 | ; | ||
| 507 | ;********************************************************************** | ||
| 508 | map_page proc near | ||
| 509 | cmp ax,[_physical_page_count] ;Q: valid physical page# ? | ||
| 510 | jae short mp_inv_phy ; N: invalid page number | ||
| 511 | ; Y: continue with it | ||
| 512 | cmp bx,0FFFFh ;Q: unmap ? | ||
| 513 | je short mp_unmap_page ; Y: go ahead | ||
| 514 | |||
| 515 | xchg bx, dx | ||
| 516 | cmp dx,[bx.ht_count] ;Q: valid logical page# ? | ||
| 517 | xchg bx, dx | ||
| 518 | jae short mp_inv_log ; N: invalid page number | ||
| 519 | ; Y: continue with it | ||
| 520 | |||
| 521 | xchg bx, dx | ||
| 522 | add dx,[bx.ht_index] ; dx <-- index into _emm_page | ||
| 523 | xchg bx, dx | ||
| 524 | shl bx,1 ; bx <-- index * 2 | ||
| 525 | add bx,[_emm_page] | ||
| 526 | mov bx,[bx] ; bx <-- emm page# | ||
| 527 | call map_EMM_page | ||
| 528 | jc short mp_inv_emm_page ; emm page range error | ||
| 529 | ret | ||
| 530 | |||
| 531 | mp_unmap_page: | ||
| 532 | call unmap_page | ||
| 533 | clc | ||
| 534 | ret | ||
| 535 | |||
| 536 | mp_inv_emm_page: | ||
| 537 | mov byte ptr [bp.rAX+1],SOURCE_CORRUPTED | ||
| 538 | stc | ||
| 539 | ret | ||
| 540 | |||
| 541 | mp_inv_phy: | ||
| 542 | mov byte ptr [bp.rAX+1],PHYS_PAGE_RANGE | ||
| 543 | stc | ||
| 544 | ret | ||
| 545 | |||
| 546 | mp_inv_log: | ||
| 547 | mov byte ptr [bp.rAX+1],LOG_PAGE_RANGE | ||
| 548 | stc | ||
| 549 | ret | ||
| 550 | map_page endp | ||
| 551 | |||
| 552 | |||
| 553 | page | ||
| 554 | ;*********************************************** | ||
| 555 | ; | ||
| 556 | ; _MapHandlePage - map a handle's page | ||
| 557 | ; | ||
| 558 | ; This routine maps 4 386 pages into the address | ||
| 559 | ; space. | ||
| 560 | ; | ||
| 561 | ; ENTRY: PROTECTED MODE ONLY | ||
| 562 | ; AH = 44h = map handle page function # | ||
| 563 | ; AL = window # (physical page #) | ||
| 564 | ; BX = logical page # | ||
| 565 | ; DX = EMM handle | ||
| 566 | ; REGS on STACK: SI = not used by this function | ||
| 567 | ; SS:[EBP] -> regp stack frame | ||
| 568 | ; DS = DGROUP | ||
| 569 | ; | ||
| 570 | ; EXIT: page table entries set up | ||
| 571 | ; AH = status of this function | ||
| 572 | ; = EMM_HW_MALFUNCTION if entry in real/virtual mode. | ||
| 573 | ; | ||
| 574 | ; USED: EAX, EBX, EDX, EDI | ||
| 575 | ; | ||
| 576 | ;*********************************************** | ||
| 577 | |||
| 578 | Dword_Align _TEXT | ||
| 579 | _MapHandlePage proc near | ||
| 580 | |||
| 581 | Validate_Handle <short mhp_inv_handle> | ||
| 582 | |||
| 583 | mov byte ptr [bp.rAX+1],OK ; Assume success! | ||
| 584 | movzx eax, al ; Physical page | ||
| 585 | movzx ebx, bx ; Logical page | ||
| 586 | |||
| 587 | push eax | ||
| 588 | mov eax, cr3 | ||
| 589 | mov cr3, eax ; Flush old mapping now | ||
| 590 | pop eax | ||
| 591 | |||
| 592 | jmp map_page ; Common page mapping code | ||
| 593 | |||
| 594 | mhp_inv_handle: | ||
| 595 | mov byte ptr [bp.rAX+1], INVALID_HANDLE | ||
| 596 | ret | ||
| 597 | |||
| 598 | _MapHandlePage endp | ||
| 599 | |||
| 600 | page | ||
| 601 | ;*********************************************** | ||
| 602 | ; | ||
| 603 | ; _SavePageMap - save current page mapping | ||
| 604 | ; | ||
| 605 | ; This routine save the current page mapping context for a handle. | ||
| 606 | ; | ||
| 607 | ; ENTRY: PROTECTED MODE | ||
| 608 | ; AH = 07h = save page map function # | ||
| 609 | ; DX = EMM handle | ||
| 610 | ; REGS on STACK: SI = not used by this function | ||
| 611 | ; SS:[BP] -> regp stack frame | ||
| 612 | ; DS = DGROUP | ||
| 613 | ; | ||
| 614 | ; EXIT: current state saved | ||
| 615 | ; AH = status of this function | ||
| 616 | ; | ||
| 617 | ; USED: AX,BX,CX,DX,SI,DI | ||
| 618 | ; | ||
| 619 | ;*********************************************** | ||
| 620 | |||
| 621 | Dword_Align _TEXT | ||
| 622 | _SavePageMap proc near | ||
| 623 | cmp [_page_frame_pages], 4 | ||
| 624 | jb short srpm_nopf ; no page frame | ||
| 625 | |||
| 626 | mov ax, dx ; Save for later | ||
| 627 | Validate_Handle <short srpm_inv_handle> | ||
| 628 | ; check state of handle's page area | ||
| 629 | imul bx,ax,SIZE SaveMap_struc ; BX = offset within Save Area for | ||
| 630 | ; this handle's save area | ||
| 631 | lea di,_save_map[bx] ; DS:DI points to handle's save area | ||
| 632 | cmp [di].s_handle,NULL_HANDLE | ||
| 633 | ;Q: save area in use ? | ||
| 634 | jne short spm_prev_saved ; Y: return error | ||
| 635 | ; N: use it now | ||
| 636 | cld | ||
| 637 | push ds | ||
| 638 | pop es | ||
| 639 | stosw ; store handle # in s_handle | ||
| 640 | Get_FRS_window SI ; Current FRS page mappings | ||
| 641 | movsd ; move to save area | ||
| 642 | movsd ; Lim 3.2 has only 4 page frames | ||
| 643 | |||
| 644 | mov byte ptr [bp.rAX+1],OK ; ok return | ||
| 645 | ret | ||
| 646 | |||
| 647 | spm_prev_saved: | ||
| 648 | mov byte ptr [bp.rAX+1],MAP_PREV_SAVED | ||
| 649 | ret | ||
| 650 | |||
| 651 | srpm_inv_handle: ; Shared error returns | ||
| 652 | mov byte ptr [bp.rAX+1],INVALID_HANDLE | ||
| 653 | ret | ||
| 654 | |||
| 655 | srpm_nopf: | ||
| 656 | mov byte ptr [bp.rAX+1], EMM_HW_MALFUNCTION ; No page frame!!! | ||
| 657 | ret | ||
| 658 | |||
| 659 | _SavePageMap endp | ||
| 660 | |||
| 661 | page | ||
| 662 | ;*********************************************** | ||
| 663 | ; | ||
| 664 | ; _RestorePageMap - restore handle's saved page mapping | ||
| 665 | ; | ||
| 666 | ; This routine restores the current page mapping context | ||
| 667 | ; from a handle's save area. | ||
| 668 | ; | ||
| 669 | ; ENTRY: PROTECTED MODE ONLY | ||
| 670 | ; AH = 08h = restore page map function # | ||
| 671 | ; DX = EMM handle | ||
| 672 | ; REGS on STACK: SI = not used by this function | ||
| 673 | ; SS:[BP] -> regp stack frame | ||
| 674 | ; DS = DGROUP | ||
| 675 | ; | ||
| 676 | ; EXIT: current state restored | ||
| 677 | ; AH = status of this function | ||
| 678 | ; | ||
| 679 | ; USED: AX,BX,CX,DX,SI,DI | ||
| 680 | ; | ||
| 681 | ;*********************************************** | ||
| 682 | |||
| 683 | Dword_Align _TEXT | ||
| 684 | _RestorePageMap proc near | ||
| 685 | cmp [_page_frame_pages], 4 | ||
| 686 | jb short srpm_nopf ; no page frame | ||
| 687 | |||
| 688 | mov ax, dx ; Save for later | ||
| 689 | Validate_Handle srpm_inv_handle | ||
| 690 | ; check state of handle's page area | ||
| 691 | imul bx,ax,SIZE SaveMap_struc ; BX = offset within Save Area for | ||
| 692 | ; this handle's save area | ||
| 693 | lea si,_save_map[bx] ; DS:SI points to handle's save area | ||
| 694 | cmp [si].s_handle,NULL_HANDLE | ||
| 695 | ;Q: save area in use ? | ||
| 696 | je short rpm_no_map_saved ; N: return error | ||
| 697 | ; Y: restore it | ||
| 698 | |||
| 699 | mov byte ptr [bp.rAX+1],OK ; Assume success | ||
| 700 | mov [si].s_handle,NULL_HANDLE ; null handle's save area | ||
| 701 | |||
| 702 | lea si,[si].s_map ; SI -> handle's save area | ||
| 703 | Get_FRS_window DI ; Get pointer to current window | ||
| 704 | push ds | ||
| 705 | pop es ; ES <-- DGROUP | ||
| 706 | cld | ||
| 707 | movsd ; restore 4 words | ||
| 708 | movsd ; Lim 3.2 has only 4 page frames | ||
| 709 | jmp _set_windows ; Restore mapping | ||
| 710 | |||
| 711 | rpm_no_map_saved: | ||
| 712 | mov byte ptr [bp.rAX+1],NO_MAP_SAVED | ||
| 713 | ret | ||
| 714 | |||
| 715 | _RestorePageMap endp | ||
| 716 | |||
| 717 | page | ||
| 718 | ;*********************************************** | ||
| 719 | ; | ||
| 720 | ; _GetSetPageMap - get/set page map to/from external save area | ||
| 721 | ; | ||
| 722 | ; This routine stores the current page mapping context (Intel | ||
| 723 | ; compatible form for now) to an external save area and/or restores | ||
| 724 | ; the current page mapping context from an external save area. | ||
| 725 | ; | ||
| 726 | ; ENTRY: PROTECTED MODE ONLY | ||
| 727 | ; AH = 4Eh = Get/Set page map function number | ||
| 728 | ; or AH = 5Ch = Get/Set large page map function number | ||
| 729 | ; AL = SUBFUNCTION CODE | ||
| 730 | ; AL = 0 => Get page map | ||
| 731 | ; AL = 1 => Set page map | ||
| 732 | ; AL = 2 => Get and Set page map | ||
| 733 | ; AL = 3 => return size of page map | ||
| 734 | ; REGS on STACK: SI = not used by this function | ||
| 735 | ; SS:[BP] -> regp stack frame | ||
| 736 | ; DS = DGROUP | ||
| 737 | ; | ||
| 738 | ; EXIT: current state saved / restored | ||
| 739 | ; AH = status of this function | ||
| 740 | ; | ||
| 741 | ; USED: BX,CX,DX,SI,DI | ||
| 742 | ; | ||
| 743 | ;*********************************************** | ||
| 744 | Dword_Align _TEXT | ||
| 745 | _GetSetPageMap proc near | ||
| 746 | |||
| 747 | cmp al,GSPM_GET ;Q: get page map subfunction ? | ||
| 748 | je short _get_map ; Y: get it | ||
| 749 | |||
| 750 | cmp al,GSPM_SET ;Q: set page map subfunction ? | ||
| 751 | je _set_map ; Y: set it | ||
| 752 | |||
| 753 | cmp al,GSPM_GETSET ;Q: get & set page map subfunction ? | ||
| 754 | jne short gspm_chk_size ; N: check for size function | ||
| 755 | call _get_map ; Y: get current map first | ||
| 756 | jmp short _set_map ; set new one | ||
| 757 | |||
| 758 | gspm_chk_size: | ||
| 759 | cmp al, GSPM_SIZE ;Q: return map size subfunction ? | ||
| 760 | jne short gspm_inv_subfun ; N: return invalid subfunction | ||
| 761 | |||
| 762 | mov al, [_cntxt_bytes] ; size of map | ||
| 763 | mov ah, OK ; ok return | ||
| 764 | mov word ptr [bp.rAX], ax | ||
| 765 | ret | ||
| 766 | |||
| 767 | gspm_inv_subfun: | ||
| 768 | mov byte ptr [bp.rAX+1],INVALID_SUBFUNCTION | ||
| 769 | ret | ||
| 770 | |||
| 771 | gspm_inv_fun: | ||
| 772 | mov byte ptr [bp.rAX+1],INVALID_FUNCTION | ||
| 773 | ret | ||
| 774 | |||
| 775 | _GetSetPageMap endp | ||
| 776 | |||
| 777 | page | ||
| 778 | ;*********************************************** | ||
| 779 | ; | ||
| 780 | ; _get_map - save current mapping register state to external area | ||
| 781 | ; | ||
| 782 | ; ENTRY: on stack | ||
| 783 | ; clients ES:DI -> client's buffer for state | ||
| 784 | ; SS:[BP] -> regp stack frame | ||
| 785 | ; DS = DGROUP | ||
| 786 | ; | ||
| 787 | ; EXIT: state stored in client's buffer | ||
| 788 | ; return code set on stack | ||
| 789 | ; | ||
| 790 | ; USED: AX,BX,CX,DX,SI,DI,ES | ||
| 791 | ; | ||
| 792 | ; DESCRIPTION: This function saves the current mapping | ||
| 793 | ; into the save area specified. | ||
| 794 | ; | ||
| 795 | ;*********************************************** | ||
| 796 | Dword_Align _TEXT | ||
| 797 | _get_map proc | ||
| 798 | |||
| 799 | cld | ||
| 800 | call _dest_addr ; DX:AX ptr for client's buff | ||
| 801 | mov es,dx | ||
| 802 | mov di,ax ; ES:DI pts to clients buffer | ||
| 803 | |||
| 804 | Get_FRS_window SI ; Get pointer to current window | ||
| 805 | movzx ecx, [_cntxt_pages] | ||
| 806 | mov ax, cx | ||
| 807 | stosw ; save # pages | ||
| 808 | shr cx, 1 ; now dwords | ||
| 809 | rep movsd ; mov bytes to current map area | ||
| 810 | mov byte ptr [bp.rAX+1],OK ; ok return | ||
| 811 | ret | ||
| 812 | |||
| 813 | _get_map endp | ||
| 814 | |||
| 815 | page | ||
| 816 | ;*********************************************** | ||
| 817 | ; | ||
| 818 | ; _set_map - restore mapping register state | ||
| 819 | ; | ||
| 820 | ; ENTRY: on stack | ||
| 821 | ; clients DS:SI -> client's buffer containing state to restore | ||
| 822 | ; SS:[BP] -> regp stack frame | ||
| 823 | ; DS = DGROUP | ||
| 824 | ; | ||
| 825 | ; EXIT: state restored from client's buffer | ||
| 826 | ; return code set on stack | ||
| 827 | ; CLC => no errors | ||
| 828 | ; STC => error occurred | ||
| 829 | ; | ||
| 830 | ; USED: EAX,BX,CX,DX,SI,DI,ES | ||
| 831 | ; | ||
| 832 | ; | ||
| 833 | ; DESCRIPTION: This function restores the mapping from the state info input. | ||
| 834 | ; The mapping is assumed to be the same as in the | ||
| 835 | ; save_current_map function. The count in the saved | ||
| 836 | ; state is verified. | ||
| 837 | ; | ||
| 838 | ;*********************************************** | ||
| 839 | Dword_Align _TEXT | ||
| 840 | _set_map proc near | ||
| 841 | |||
| 842 | mov byte ptr [bp.rAX+1],OK ; Assume success | ||
| 843 | Get_FRS_window DI ; Get pointer to current window | ||
| 844 | ; before DS gets trashed | ||
| 845 | push ds | ||
| 846 | pop es ; use ES to address data | ||
| 847 | push dx | ||
| 848 | mov si, ax | ||
| 849 | call _source_addr ; DX:AX ptr for client's buff | ||
| 850 | mov ds,dx | ||
| 851 | xchg si,ax ; DS:SI pts to clients buffer | ||
| 852 | pop dx | ||
| 853 | |||
| 854 | cld | ||
| 855 | movzx ecx, es:[_cntxt_pages] ; number of words in mapping | ||
| 856 | lodsw ; saved size | ||
| 857 | cmp ax, cx ; should be this | ||
| 858 | jne short sm_inv_source ; Wrong, saved data corrupted | ||
| 859 | shr cx, 1 ; now a word count | ||
| 860 | rep movsd | ||
| 861 | push es | ||
| 862 | pop ds ; DS <-- DGROUP | ||
| 863 | jmp _set_windows ; make it effective | ||
| 864 | |||
| 865 | sm_inv_source: | ||
| 866 | mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED | ||
| 867 | ret | ||
| 868 | |||
| 869 | sm_exit: | ||
| 870 | ret | ||
| 871 | |||
| 872 | _set_map endp | ||
| 873 | |||
| 874 | page | ||
| 875 | ;*********************************************** | ||
| 876 | ; | ||
| 877 | ; _set_windows - re-map all mapped physical pages | ||
| 878 | ; | ||
| 879 | ; This routine maps all mapped 386 pages of the EMM page frame into the | ||
| 880 | ; linear address space for the page frame. | ||
| 881 | ; | ||
| 882 | ; ENTRY: PROTECTED MODE ONLY | ||
| 883 | ; DS = DGROUP | ||
| 884 | ; SS:[BP] -> regp stack frame | ||
| 885 | ; | ||
| 886 | ; EXIT: page tables changed to map these pages. | ||
| 887 | ; _current_map contents initialized. | ||
| 888 | ; | ||
| 889 | ; uses: | ||
| 890 | ; FLAGS, EAX, EBX, ECX, ESI, EDI | ||
| 891 | ; | ||
| 892 | ;*********************************************** | ||
| 893 | ; | ||
| 894 | _set_windows proc near | ||
| 895 | ; | ||
| 896 | xor ax, ax ; start from PHYS page 0 | ||
| 897 | Get_FRS_Window SI ; SI <-- current FRS map | ||
| 898 | sw_loop: | ||
| 899 | mov bx, word ptr [si] ; BX <-- emm page # | ||
| 900 | add si, 2 ; prepare for next PHYS page | ||
| 901 | cmp bx, 0FFFFh ; not mapped ? | ||
| 902 | je sw_unmap_page ; Y: unmap it | ||
| 903 | cmp bx, [_total_pages] ; emm page out of range ? | ||
| 904 | ja sw_corrupt ; Y: error | ||
| 905 | mov di, bx | ||
| 906 | shl di, 2 ; SI <-- _pft386 offset of emm page | ||
| 907 | add di, [_pft386] | ||
| 908 | cmp dword ptr [di], 0 ; pte not mapped ? | ||
| 909 | je sw_corrupt ; Y: error | ||
| 910 | push eax | ||
| 911 | call map_EMM_page ; map a page | ||
| 912 | pop eax | ||
| 913 | sw_done_page: | ||
| 914 | inc ax | ||
| 915 | cmp ax, [_physical_page_count] | ||
| 916 | jb sw_loop ; next page | ||
| 917 | |||
| 918 | mov eax, cr3 | ||
| 919 | mov cr3, eax ; flush TLB | ||
| 920 | ret | ||
| 921 | |||
| 922 | sw_unmap_page: | ||
| 923 | push eax | ||
| 924 | call unmap_Page | ||
| 925 | pop eax | ||
| 926 | jmp short sw_done_page | ||
| 927 | |||
| 928 | sw_corrupt: | ||
| 929 | mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED | ||
| 930 | pop dx | ||
| 931 | ret | ||
| 932 | |||
| 933 | _set_windows endp | ||
| 934 | |||
| 935 | page | ||
| 936 | ;******************************************************************************* | ||
| 937 | ; | ||
| 938 | ; LIM 4.0 EXTRAS for Windows | ||
| 939 | ; | ||
| 940 | ;******************************************************************************* | ||
| 941 | |||
| 942 | ;*********************************************** | ||
| 943 | ; | ||
| 944 | ; _GetSetPartial - get/set partial page map to/from external save area | ||
| 945 | ; | ||
| 946 | ; This routine stores the current page mapping context | ||
| 947 | ; to an external save area and/or restores the current page | ||
| 948 | ; mapping context from an external save area. | ||
| 949 | ; | ||
| 950 | ; ENTRY: PROTECTED MODE ONLY | ||
| 951 | ; AH = 4Fh = Get/Set page map function number | ||
| 952 | ; AL = SUBFUNCTION CODE | ||
| 953 | ; AL = 0 => Get page map | ||
| 954 | ; AL = 1 => Set page map | ||
| 955 | ; AL = 2 => return size of page map | ||
| 956 | ; REGS on STACK: SI = not used by this function | ||
| 957 | ; SS:[BP] -> regp stack frame | ||
| 958 | ; DS = DGROUP | ||
| 959 | ; | ||
| 960 | ; EXIT: current state saved / restored | ||
| 961 | ; AH = status of this function | ||
| 962 | ; | ||
| 963 | ; USED: BX,CX,DX,SI,DI | ||
| 964 | ; | ||
| 965 | ;*********************************************** | ||
| 966 | _GetSetPartial proc near | ||
| 967 | cmp al, 0 ; Get...? | ||
| 968 | jne gsppm_not0 | ||
| 969 | |||
| 970 | call _source_addr ; uses AX, DX | ||
| 971 | mov fs, dx | ||
| 972 | mov si, ax | ||
| 973 | call _dest_addr ; uses AX, DX | ||
| 974 | mov es, dx | ||
| 975 | mov di, ax | ||
| 976 | cld | ||
| 977 | lods word ptr fs:[si] | ||
| 978 | stosw ; Save count in save area | ||
| 979 | or ax, ax | ||
| 980 | jz gsppm_ok ; nothing to do | ||
| 981 | movzx ecx, ax | ||
| 982 | |||
| 983 | mov dx, [_mappable_page_count] | ||
| 984 | cmp cx, dx | ||
| 985 | ja gsppm_inv_phys | ||
| 986 | gsppm_get_loop: | ||
| 987 | lods word ptr fs:[si] ; Get segment | ||
| 988 | shr ax, 10 ; 16k page number | ||
| 989 | sub ax, CONV_STRT_PG ; first page in emm_mpindex arr | ||
| 990 | jb gsppm_inv_seg ; only pages above 256k | ||
| 991 | mov bx, ax | ||
| 992 | mov al, EMM_MPindex[bx] ; convert to physical page | ||
| 993 | cmp al, -1 ; does it exist | ||
| 994 | je gsppm_inv_seg | ||
| 995 | mov bx, ax | ||
| 996 | shl bx, 2 | ||
| 997 | lea ax, _mappable_pages[bx] | ||
| 998 | mov bx, ax | ||
| 999 | mov bx, [bx.mappable_seg] ; segment for this page | ||
| 1000 | cmp bx, fs:[si-2] | ||
| 1001 | jne gsppm_inv_seg ; must match exactly | ||
| 1002 | mov bx, ax | ||
| 1003 | movzx ebx, [bx.mappable_pg] ; the physical page | ||
| 1004 | cmp bx, dx | ||
| 1005 | ja gsppm_inv_seg | ||
| 1006 | mov ax, bx | ||
| 1007 | stosw ; Save physical page | ||
| 1008 | Get_FRS_window BX ; Get pointer to current window | ||
| 1009 | add bx, ax ; get ptr to emm page# in FRS | ||
| 1010 | add bx, ax | ||
| 1011 | mov ax, [bx] | ||
| 1012 | stosw ; and current mapping | ||
| 1013 | loop gsppm_get_loop | ||
| 1014 | |||
| 1015 | gsppm_ok: | ||
| 1016 | mov byte ptr [bp.rAX+1], OK | ||
| 1017 | ret | ||
| 1018 | |||
| 1019 | gsppm_not0: | ||
| 1020 | cmp al, 1 ; Set...? | ||
| 1021 | jne gsppm_not1 | ||
| 1022 | ; Set Partial Page Map | ||
| 1023 | call _source_addr ; uses AX, DX | ||
| 1024 | mov fs, dx | ||
| 1025 | mov si, ax | ||
| 1026 | movzx ecx, word ptr fs:[si] ; Get count from save area | ||
| 1027 | add si, 2 | ||
| 1028 | jecxz gsppm_ok ; Zero count, do nothing | ||
| 1029 | |||
| 1030 | Get_FRS_window DX ; Get pointer to current window | ||
| 1031 | cmp cx, [_mappable_page_count] | ||
| 1032 | ja short gsppm_corrupt ; can't be more than phys pages | ||
| 1033 | gsppm_set_loop: | ||
| 1034 | push esi | ||
| 1035 | movzx eax, word ptr fs:[si] ; Get Physical page | ||
| 1036 | cmp ax, [_mappable_page_count] | ||
| 1037 | jae gsppm_sl_bad | ||
| 1038 | |||
| 1039 | movzx esi, word ptr fs:[si+2] ; Get mapping (emm page#) | ||
| 1040 | mov di,dx | ||
| 1041 | add di,ax | ||
| 1042 | add di,ax ; di <-- current FRS phy page | ||
| 1043 | mov [di], si ; Save new mapping | ||
| 1044 | |||
| 1045 | cmp si, 0FFFFh ; Unmapped? | ||
| 1046 | je short gsppm_unmap ; yes, go unmap it | ||
| 1047 | cmp si, [_total_pages] ; valid page? | ||
| 1048 | jae short gsppm_sl_bad ; no, fail | ||
| 1049 | |||
| 1050 | mov bx, si ; bx <-- emm page# | ||
| 1051 | ; ax <-- phys page# | ||
| 1052 | call map_EMM_page | ||
| 1053 | |||
| 1054 | gsppm_set_done: | ||
| 1055 | pop esi | ||
| 1056 | add esi, 4 ; Next page to map | ||
| 1057 | loop gsppm_set_loop | ||
| 1058 | mov eax, cr3 ; Flush TLB | ||
| 1059 | mov cr3, eax | ||
| 1060 | jmp gsppm_ok | ||
| 1061 | |||
| 1062 | gsppm_unmap: | ||
| 1063 | call unmap_page ; with ax <-- phys page# | ||
| 1064 | jmp gsppm_set_done ; On to next page | ||
| 1065 | |||
| 1066 | gsppm_sl_bad: | ||
| 1067 | pop esi | ||
| 1068 | gsppm_corrupt: | ||
| 1069 | mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED | ||
| 1070 | ret | ||
| 1071 | |||
| 1072 | gsppm_not1: | ||
| 1073 | cmp al, 2 ; Size? | ||
| 1074 | jne gspm_inv_subfun | ||
| 1075 | cmp bx, [_mappable_page_count] ; # of page frames | ||
| 1076 | ja short gsppm_inv_phys | ||
| 1077 | shl bx, 2 ; Size = pages * 4 + 2 | ||
| 1078 | add bx, 2 | ||
| 1079 | mov byte ptr [bp.rAX], bl | ||
| 1080 | jmp gsppm_ok | ||
| 1081 | |||
| 1082 | gsppm_inv_subfun: | ||
| 1083 | mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION | ||
| 1084 | ret | ||
| 1085 | |||
| 1086 | gsppm_inv_phys: | ||
| 1087 | gsppm_inv_seg: | ||
| 1088 | mov byte ptr [bp.rAX+1], PHYS_PAGE_RANGE | ||
| 1089 | ret | ||
| 1090 | |||
| 1091 | _GetSetPartial endp | ||
| 1092 | |||
| 1093 | page | ||
| 1094 | ;*********************************************** | ||
| 1095 | ; | ||
| 1096 | ; _MapHandleArray - map an array of a handle's pages | ||
| 1097 | ; | ||
| 1098 | ; This routine maps the physical pages according to | ||
| 1099 | ; an array of mappings. | ||
| 1100 | ; | ||
| 1101 | ; ENTRY: PROTECTED MODE ONLY | ||
| 1102 | ; AH = 50h = map handle page function # | ||
| 1103 | ; AL = Subfunction: 0) Physical pages described by their number | ||
| 1104 | ; 1) Physical pages described by segment | ||
| 1105 | ; CX = number of pages to be mapped | ||
| 1106 | ; DX = EMM handle | ||
| 1107 | ; REGS on STACK DS:SI = array of mappings | ||
| 1108 | ; SS:[BP] -> regp stack frame | ||
| 1109 | ; DS = DGROUP | ||
| 1110 | ; NOTE: | ||
| 1111 | ; There is a second entry point for this procedure at the label | ||
| 1112 | ; MapHandleArray_Entry_2. The entry conditions for this are identical | ||
| 1113 | ; to those specified above except that ESI points to the mapping array-- | ||
| 1114 | ; the DS:SI on the stack are ignored. Also, the value in AH is undefined. | ||
| 1115 | ; This entry point is used by the AlterMapAndJump and AlterMapAndCall | ||
| 1116 | ; functions. | ||
| 1117 | ; | ||
| 1118 | ; EXIT: context block ve_window set up | ||
| 1119 | ; page table entries set up | ||
| 1120 | ; AH = status of this function | ||
| 1121 | ; = EMM_HW_MALFUNCTION if entry in real/virtual mode. | ||
| 1122 | ; | ||
| 1123 | ; USED: AX,BX,DX,SI,DI,FS | ||
| 1124 | ; | ||
| 1125 | ;*********************************************** | ||
| 1126 | Dword_Align _TEXT | ||
| 1127 | _MapHandleArray proc near | ||
| 1128 | mov si, ax | ||
| 1129 | push dx | ||
| 1130 | call _source_addr ; DX:AX <-- mapping array | ||
| 1131 | xchg si, ax | ||
| 1132 | mov fs, dx | ||
| 1133 | pop dx ; FS:SI <-- mapping array | ||
| 1134 | |||
| 1135 | MapHandleArray_Entry_2: | ||
| 1136 | cmp al, 1 ; Q: Is subfunction 0 or 1? | ||
| 1137 | ja mha_inv_sub ; N: Invalid subfunction | ||
| 1138 | |||
| 1139 | Validate_Handle <mha_inv_handle> | ||
| 1140 | |||
| 1141 | mov byte ptr [bp.rAX+1], OK ; Assume success | ||
| 1142 | movzx ecx, cx | ||
| 1143 | jecxz short mha_exit ; none to do, just return | ||
| 1144 | |||
| 1145 | or al, al ; which subfunction? | ||
| 1146 | jnz short mha_sub1 ; subfunction 1? | ||
| 1147 | |||
| 1148 | ; | ||
| 1149 | ; Subfunction 0: array contains logical and physical | ||
| 1150 | ; page numbers. | ||
| 1151 | ; | ||
| 1152 | mha_sub0: | ||
| 1153 | movzx eax, fs:[si.mha0_phys_pg] ; physical page number | ||
| 1154 | movzx ebx, fs:[si.mha0_log_pg] ; logical page number | ||
| 1155 | call map_page ; map it if possible | ||
| 1156 | jc short mha_exit ; Error code already set | ||
| 1157 | add si, size mha_array0 | ||
| 1158 | loop mha_sub0 | ||
| 1159 | jmp short mha_exit | ||
| 1160 | |||
| 1161 | ; | ||
| 1162 | ; Subfunction 1: array contains logical page number and | ||
| 1163 | ; segment numbers corresponding to the | ||
| 1164 | ; desired physical pages. | ||
| 1165 | ; | ||
| 1166 | mha_sub1: | ||
| 1167 | mov di, fs:[si.mha1_seg] ; segment to map | ||
| 1168 | mov ax, di ; save for later | ||
| 1169 | shr di, 10 ; 16k page number | ||
| 1170 | sub di, CONV_STRT_PG ; first page in emm_mpindex arr | ||
| 1171 | jb short mha_inv_seg ; only pages above 256k | ||
| 1172 | movsx edi, EMM_MPindex[di] ; convert to physical page | ||
| 1173 | cmp edi, -1 ; does it exist | ||
| 1174 | je short mha_inv_seg | ||
| 1175 | shl di, 2 ; index * 4 | ||
| 1176 | lea di, _mappable_pages[di] | ||
| 1177 | cmp ax, [di.mappable_seg] ; segment for this page | ||
| 1178 | jne short mha_inv_seg ; must match exactly | ||
| 1179 | movzx eax, [di.mappable_pg] ; the physical page | ||
| 1180 | movzx ebx, fs:[si.mha1_log_pg] ; the logical page | ||
| 1181 | call map_page ; try to map it | ||
| 1182 | jc short mha_exit ; error code already set | ||
| 1183 | add si, size mha_array1 | ||
| 1184 | loop mha_sub1 ; back for next segment to map | ||
| 1185 | |||
| 1186 | mha_exit: | ||
| 1187 | mov eax, cr3 ; Always clear TLB, we may have | ||
| 1188 | mov cr3, eax ; mapped pages before an error | ||
| 1189 | ret | ||
| 1190 | ; ERRORS... | ||
| 1191 | mha_inv_handle: | ||
| 1192 | mov byte ptr [bp.rAX+1], INVALID_HANDLE | ||
| 1193 | ret | ||
| 1194 | mha_inv_sub: | ||
| 1195 | mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION | ||
| 1196 | ret | ||
| 1197 | mha_inv_seg: | ||
| 1198 | mov byte ptr [bp.rAX+1], PHYS_PAGE_RANGE | ||
| 1199 | jmp mha_exit | ||
| 1200 | |||
| 1201 | _MapHandleArray endp | ||
| 1202 | |||
| 1203 | |||
| 1204 | |||
| 1205 | page | ||
| 1206 | ;*********************************************** | ||
| 1207 | ; | ||
| 1208 | ; _AlterMapAndJump - map an array of a handle's pages and Jump to a | ||
| 1209 | ; a specified address | ||
| 1210 | ; | ||
| 1211 | ; This routine maps pages using the MapHandleArray procedure and jumps | ||
| 1212 | ; to the specified address | ||
| 1213 | ; | ||
| 1214 | ; ENTRY: PROTECTED MODE ONLY | ||
| 1215 | ; AL = Mapping method -- 0 = Physical pages, 1 = Segments | ||
| 1216 | ; DX = EMM handle | ||
| 1217 | ; REGS on STACK | ||
| 1218 | ; REGS on STACK -- DS:SI -> Map and Jump structure | ||
| 1219 | ; SS:[BP] -> regp stack frame | ||
| 1220 | ; DS = DGROUP | ||
| 1221 | ; | ||
| 1222 | ; EXIT: context block ve_window set up | ||
| 1223 | ; page table entries set up | ||
| 1224 | ; AH = status of this function | ||
| 1225 | ; = EMM_HW_MALFUNCTION if entry in real/virtual mode. | ||
| 1226 | ; Address specified in Map and Jump structure will be new return address | ||
| 1227 | ; | ||
| 1228 | ; USED: AX,BX,CX,SI,DI,FS,GS | ||
| 1229 | ; | ||
| 1230 | ;********************************************** | ||
| 1231 | |||
| 1232 | _AlterMapAndJump PROC NEAR | ||
| 1233 | |||
| 1234 | push dx | ||
| 1235 | mov si, ax | ||
| 1236 | call _source_addr ; DX:AX <-- map & jump struct | ||
| 1237 | mov gs, dx | ||
| 1238 | xchg si, ax ; GS:SI <-- map & jump struct | ||
| 1239 | pop dx | ||
| 1240 | push si | ||
| 1241 | push ax | ||
| 1242 | push dx ; save EMM handle | ||
| 1243 | mov dx, WORD PTR gs:[si.maj_map_address] ; AX:DX <-- map array | ||
| 1244 | mov ax, WORD PTR gs:[si.maj_map_address+2] | ||
| 1245 | Set_EMM_GDT EMM2_GSEL | ||
| 1246 | mov fs, bx ; FS:0 <-- map array | ||
| 1247 | pop dx ; restore handle | ||
| 1248 | pop ax ; restore subfunction | ||
| 1249 | movzx ecx, byte ptr gs:[si.maj_log_phys_map_len] ; Length of map | ||
| 1250 | xor si, si ; FS:SI <-- map array | ||
| 1251 | call MapHandleArray_Entry_2 ; Map the array | ||
| 1252 | pop si | ||
| 1253 | |||
| 1254 | mov ah, byte ptr [bp.rAX+1] | ||
| 1255 | or ah, ah | ||
| 1256 | jnz SHORT AMJ_Error | ||
| 1257 | mov eax, dword ptr gs:[si.maj_target_address] | ||
| 1258 | mov word ptr [bp.retaddr], ax ; Put jump address in place of | ||
| 1259 | shr eax, 16 ; old IRET return address | ||
| 1260 | mov word ptr [bp.rCS], ax | ||
| 1261 | ; | ||
| 1262 | ; now, pop 5 words from client's stack because we are not | ||
| 1263 | ; going to go back. (See AlterMapAndCall for client's | ||
| 1264 | ; Stack frame structure) | ||
| 1265 | ; | ||
| 1266 | mov edi, dword ptr [bp.rFS+2+VTFO.VMTF_ESP] ; clients's ESP | ||
| 1267 | add edi, 5 * 2 ; "pop" 5 words | ||
| 1268 | mov dword ptr [bp.rFS+2+VTFO.VMTF_ESP], edi ; save it | ||
| 1269 | ; | ||
| 1270 | ; tell EMMpEntry to patch CS:IP onto its' iretd stack frame | ||
| 1271 | ; | ||
| 1272 | or word ptr [bp.PFlag], PFLAG_PATCH_CS_IP | ||
| 1273 | AMJ_Error: ; Do the jump | ||
| 1274 | ret | ||
| 1275 | |||
| 1276 | _AlterMapAndJump ENDP | ||
| 1277 | |||
| 1278 | |||
| 1279 | page | ||
| 1280 | ;*********************************************** | ||
| 1281 | ; | ||
| 1282 | ; _AlterMapAndCall - map an array of a handle's pages and call a procedure | ||
| 1283 | ; at a specified address (similar to a FAR call) | ||
| 1284 | ; This function pushes the return address on the | ||
| 1285 | ; client's stack and Jumps to the specified procedure. | ||
| 1286 | ; The "Called" procedure will return to AMC_return_address | ||
| 1287 | ; | ||
| 1288 | ; ENTRY: PROTECTED MODE ONLY | ||
| 1289 | ; AL = Subfunction -- 0 = Map phys pages, 1 = Map segs, 2 = Frame size | ||
| 1290 | ; DX = EMM handle | ||
| 1291 | ; REGS on STACK DS:SI = Map and Call structure | ||
| 1292 | ; SS:[BP] -> regp stack frame | ||
| 1293 | ; DS = DGROUP | ||
| 1294 | ; | ||
| 1295 | ; EXIT: context block ve_window set up | ||
| 1296 | ; page table entries set up | ||
| 1297 | ; Transfer Space pushed on client's stack | ||
| 1298 | ; Return address CS and IP will point to called procedure | ||
| 1299 | ; AH = status of this function | ||
| 1300 | ; = EMM_HW_MALFUNCTION if entry in real/virtual mode. | ||
| 1301 | ; | ||
| 1302 | ; USED: AX,BX,CX,DX,SI,DI | ||
| 1303 | ; | ||
| 1304 | ;*********************************************** | ||
| 1305 | |||
| 1306 | _AlterMapAndCall PROC NEAR | ||
| 1307 | |||
| 1308 | cmp al, 2 ; Q: Which subfuction ? | ||
| 1309 | ja AMC_inv_sub ; >2: invalid subfunction | ||
| 1310 | je AMC_Stack_Fram_Size ; =2: Stack frame size subfuncion | ||
| 1311 | ; <2: map and call | ||
| 1312 | push dx | ||
| 1313 | mov si, ax | ||
| 1314 | call _source_addr ; DX:AX <-- map & call structure | ||
| 1315 | mov gs, dx | ||
| 1316 | xchg si, ax ; GS:SI <-- map & call structure | ||
| 1317 | pop dx | ||
| 1318 | ; | ||
| 1319 | ; check new and old map's length | ||
| 1320 | ; | ||
| 1321 | xor ch, ch | ||
| 1322 | mov cl, byte ptr gs:[si.mac_old_page_map_len] ; CX = Length of old map | ||
| 1323 | cmp cx, [_physical_page_count] | ||
| 1324 | jae AMC_inv_phys_pages | ||
| 1325 | mov cl, byte ptr gs:[si.mac_new_page_map_len] ; CX = Length of new map | ||
| 1326 | cmp cx, [_physical_page_count] | ||
| 1327 | jae AMC_inv_phys_pages | ||
| 1328 | ; | ||
| 1329 | ; get client's SS:ESP so we can push stuffs on it | ||
| 1330 | ; | ||
| 1331 | push ax | ||
| 1332 | push dx | ||
| 1333 | |||
| 1334 | mov edi, dword ptr [bp.rFS+2+VTFO.VMTF_ESP] ; clients's ESP | ||
| 1335 | mov ax, word ptr [bp.rFS+2+VTFO.VMTF_SS] ; client's SS | ||
| 1336 | xor dx, dx ; AX:DX <-- Seg:Off of Client's Stack | ||
| 1337 | |||
| 1338 | push ax ; client's Stack Segment | ||
| 1339 | Set_EMM_GDT EMM2_GSEL | ||
| 1340 | push bx ; client's Stack Selector | ||
| 1341 | ; | ||
| 1342 | ; get CS's Base to "push" on stack for later retf from client | ||
| 1343 | ; | ||
| 1344 | push GDTD_GSEL | ||
| 1345 | pop es ; ES:0 <-- GDT | ||
| 1346 | mov bx, cs ; selector | ||
| 1347 | and bl, SEL_LOW_MASK | ||
| 1348 | mov dx, word ptr es:[bx + 2] ; get lower 16 bit of Base | ||
| 1349 | mov al, byte ptr es:[bx + 4] ; get upper 8 bit of Base | ||
| 1350 | shr dx, 4 | ||
| 1351 | shl al, 4 | ||
| 1352 | or dh, al ; get the segment value | ||
| 1353 | mov bx, dx ; into BX | ||
| 1354 | |||
| 1355 | pop es ; ES:DI <-- client's SS | ||
| 1356 | pop cx ; CX <-- Client's stack Segment | ||
| 1357 | |||
| 1358 | pop dx | ||
| 1359 | pop ax | ||
| 1360 | ; | ||
| 1361 | ; save client's stack segment and target address on stack | ||
| 1362 | ; cause they (CX and EMM1_GSEL) get destroy | ||
| 1363 | ; | ||
| 1364 | push cx | ||
| 1365 | push word ptr gs:[si].mac_target_address+2 | ||
| 1366 | push word ptr gs:[si].mac_target_address | ||
| 1367 | ; | ||
| 1368 | ; On the Client's stack : | ||
| 1369 | ; | ||
| 1370 | ; +-----------------+ | ||
| 1371 | ; | client's Flag | | ||
| 1372 | ; +-----------------+ | ||
| 1373 | ; | client's CS | | ||
| 1374 | ; +-----------------+ | ||
| 1375 | ; | client's IP | | ||
| 1376 | ; +-----------------+ | ||
| 1377 | ; | EMM_rEntry's CS | | ||
| 1378 | ; +-----------------+ | ||
| 1379 | ; | EMM_rEntry's IP | <-- "SS:ESP" (ES:EDI) | ||
| 1380 | ; +-----------------+ | ||
| 1381 | ; | ||
| 1382 | ; "pop" EMM_rEntry's CS:IP off the stack, save it on Ring0 stack | ||
| 1383 | ; in case thereis an error and need to restore state of stack. | ||
| 1384 | ; keep the rest (client's FLAG, CS and IP) | ||
| 1385 | ; | ||
| 1386 | push es:[di+2] ; EMM_rEntry's CS | ||
| 1387 | push es:[di] ; EMM_rEntry's IP | ||
| 1388 | add di, 2 * 2 ; "pop" | ||
| 1389 | ; | ||
| 1390 | ; save old map on stack | ||
| 1391 | ; | ||
| 1392 | movzx ecx, byte ptr gs:[si.mac_old_page_map_len] ; CX = Length of old map | ||
| 1393 | shl cx, 2 ; CX * 4 (4 bytes each entry) | ||
| 1394 | inc cx ; one more for length | ||
| 1395 | get_space_from_stack CX ; ES:DI <-- space on stack | ||
| 1396 | dec cx | ||
| 1397 | shr cx, 2 ; CX back to length in bytes | ||
| 1398 | |||
| 1399 | push ds | ||
| 1400 | push di ; save postion of stack | ||
| 1401 | push si | ||
| 1402 | push ax | ||
| 1403 | push bx | ||
| 1404 | push dx | ||
| 1405 | push cx ; save #pages | ||
| 1406 | |||
| 1407 | cld | ||
| 1408 | mov dx, word ptr gs:[si.mac_old_map_address] ; AX:DX <-- map array | ||
| 1409 | mov ax, word ptr gs:[si.mac_old_map_address+2] | ||
| 1410 | push es | ||
| 1411 | Set_EMM_GDT USER1_GSEL | ||
| 1412 | pop es | ||
| 1413 | mov ds, bx ; DS:0 <-- map array | ||
| 1414 | xor si, si | ||
| 1415 | pop cx | ||
| 1416 | mov ax, cx | ||
| 1417 | stosb ; store length of map | ||
| 1418 | |||
| 1419 | shl cx, 1 ; move word | ||
| 1420 | rep movsw | ||
| 1421 | |||
| 1422 | pop dx ; restore handle | ||
| 1423 | pop bx ; restore Segment of client Stack | ||
| 1424 | pop ax ; restore subfunction | ||
| 1425 | pop si | ||
| 1426 | pop di | ||
| 1427 | pop ds | ||
| 1428 | ; | ||
| 1429 | ; save FRS context on stack | ||
| 1430 | ; | ||
| 1431 | movzx ecx, [_cntxt_bytes] | ||
| 1432 | get_space_from_stack CX ; ES:DI <-- space on stack | ||
| 1433 | |||
| 1434 | push si | ||
| 1435 | push di | ||
| 1436 | get_FRS_Window SI ; DS:SI <-- mapping context | ||
| 1437 | shr ecx, 1 ; move words | ||
| 1438 | rep movsw | ||
| 1439 | |||
| 1440 | pop di | ||
| 1441 | pop si | ||
| 1442 | ; | ||
| 1443 | ; map new mapping | ||
| 1444 | ; | ||
| 1445 | push bx | ||
| 1446 | push ax | ||
| 1447 | push dx | ||
| 1448 | |||
| 1449 | push di ; save "stack pointer" | ||
| 1450 | push si | ||
| 1451 | push ax | ||
| 1452 | push dx ; save EMM handle | ||
| 1453 | mov dx, WORD PTR gs:[si.mac_new_map_address]; AX:DX <-- map array | ||
| 1454 | mov ax, WORD PTR gs:[si.mac_new_map_address+2] | ||
| 1455 | push es | ||
| 1456 | Set_EMM_GDT USER1_GSEL | ||
| 1457 | pop es | ||
| 1458 | mov fs, bx ; FS:0 <-- map array | ||
| 1459 | xor si, si | ||
| 1460 | pop dx ; restore handle | ||
| 1461 | pop ax ; restore subfunction | ||
| 1462 | movzx ecx, byte ptr gs:[si.mac_new_page_map_len] | ||
| 1463 | call MapHandleArray_Entry_2 ; Map the array | ||
| 1464 | pop si ; Restore structure pointer | ||
| 1465 | pop di ; restore "stack" pointer | ||
| 1466 | pop dx | ||
| 1467 | pop ax | ||
| 1468 | mov bh, byte ptr [bp.rAX+1] | ||
| 1469 | or bh, bh | ||
| 1470 | pop bx | ||
| 1471 | jnz AMC_map_Error | ||
| 1472 | ; | ||
| 1473 | ; save needed registers, return address and call address | ||
| 1474 | ; on client's stack | ||
| 1475 | ; | ||
| 1476 | dec di | ||
| 1477 | dec di ; "pre-decrement" stack | ||
| 1478 | std ; store backward | ||
| 1479 | stosw ; subfunction code | ||
| 1480 | mov ax, dx ; EMM handle | ||
| 1481 | stosw | ||
| 1482 | mov ax, ds ; DGROUP | ||
| 1483 | stosw | ||
| 1484 | mov ax, bx ; CS for return from called code | ||
| 1485 | stosw | ||
| 1486 | mov ax, offset AMC_return_address ; IP for return from called code | ||
| 1487 | mov es:[di], ax ; "push" without decrement "SP" | ||
| 1488 | cld | ||
| 1489 | ; | ||
| 1490 | ; NOW build a iretd stack frame to go back to virtual mode | ||
| 1491 | ; | ||
| 1492 | pop ax ; no error : we can throw | ||
| 1493 | pop ax ; away EMM-rEntry's CS:IP now | ||
| 1494 | |||
| 1495 | pop ax ; target address | ||
| 1496 | pop dx ; target address+2 | ||
| 1497 | pop cx ; Stack Segment | ||
| 1498 | |||
| 1499 | push 0 | ||
| 1500 | push word ptr [bp].rGS | ||
| 1501 | push 0 | ||
| 1502 | push word ptr [bp].rFS | ||
| 1503 | push 0 | ||
| 1504 | push word ptr [bp].rDS | ||
| 1505 | push 0 | ||
| 1506 | push word ptr [bp].rES | ||
| 1507 | push 0 | ||
| 1508 | push cx ; client's SS | ||
| 1509 | push edi ; client's ESP | ||
| 1510 | push PFLAG_VM ; VM bit | ||
| 1511 | mov bx, word ptr [bp].PFlag | ||
| 1512 | and bx, not PFLAG_VIRTUAL ; clear fake bit | ||
| 1513 | push bx | ||
| 1514 | push 0 | ||
| 1515 | push dx ; target address+2 | ||
| 1516 | push 0 | ||
| 1517 | push ax ; target address | ||
| 1518 | ; | ||
| 1519 | ; restore registers context from stack frame | ||
| 1520 | ; | ||
| 1521 | mov eax, dword ptr [bp].rAX | ||
| 1522 | mov ebx, dword ptr [bp].rBX | ||
| 1523 | mov ecx, dword ptr [bp].rCX | ||
| 1524 | mov edx, dword ptr [bp].rDX | ||
| 1525 | mov esi, dword ptr [bp].rSI | ||
| 1526 | mov edi, dword ptr [bp].rDI | ||
| 1527 | mov ebp, dword ptr [bp].rFS+2 ; clients's EBP | ||
| 1528 | ; | ||
| 1529 | ; return to virtual mode via iretd with calling address on stack | ||
| 1530 | ; | ||
| 1531 | iretd | ||
| 1532 | |||
| 1533 | AMC_map_Error: | ||
| 1534 | ; | ||
| 1535 | ; mapping error occur : restore state and exit | ||
| 1536 | ; | ||
| 1537 | movzx ecx, [_cntxt_bytes] | ||
| 1538 | push es | ||
| 1539 | pop ds ; DS:SI <-- stack | ||
| 1540 | xchg si, di | ||
| 1541 | release_space_to_stack CX ; DS:SI <-- space on stack | ||
| 1542 | ; | ||
| 1543 | movzx ecx, byte ptr gs:[di.mac_old_page_map_len] ; CX = Length of old map | ||
| 1544 | shl cx, 2 ; CX * 4 (4 bytes each entry) | ||
| 1545 | inc cx ; one more for length | ||
| 1546 | release_space_to_stack CX ; DS:SI <-- space on stack | ||
| 1547 | ; | ||
| 1548 | mov di, si | ||
| 1549 | mov cx, 4 | ||
| 1550 | get_space_from_stack CX ; ES:DI <-- space on stack | ||
| 1551 | pop es:[di] ; restore EMM_rEntry's CS:IP | ||
| 1552 | pop es:[di+2] | ||
| 1553 | |||
| 1554 | pop ax ; discard target addr etc | ||
| 1555 | pop ax | ||
| 1556 | pop ax | ||
| 1557 | |||
| 1558 | ret | ||
| 1559 | |||
| 1560 | AMC_Stack_Fram_Size: | ||
| 1561 | mov byte ptr [bp.rAX+1], OK ; No error | ||
| 1562 | mov ax, [_mappable_page_count] ; assume ALL mappable pages | ||
| 1563 | shl ax, 2 ; 4 bytes per page | ||
| 1564 | add ax, 1 + (3+5)*2 ; map length | ||
| 1565 | ; + 3 words already pushed by EMM_rEntry | ||
| 1566 | ; + 5 registers pushed | ||
| 1567 | add al, [_cntxt_bytes] ; FRS context | ||
| 1568 | adc ah, 0 | ||
| 1569 | mov word ptr [bp.rBX], ax | ||
| 1570 | ret | ||
| 1571 | |||
| 1572 | AMC_inv_phys_pages: | ||
| 1573 | mov byte ptr [bp.rAX+1], PHYS_PAGE_RANGE | ||
| 1574 | ret | ||
| 1575 | |||
| 1576 | AMC_inv_sub: | ||
| 1577 | mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION | ||
| 1578 | ret | ||
| 1579 | |||
| 1580 | _AlterMapAndCall ENDP | ||
| 1581 | |||
| 1582 | |||
| 1583 | ;****************************************************************************** | ||
| 1584 | ; | ||
| 1585 | ; AMC_return_address -- Return from procedure called through a Map & Call | ||
| 1586 | ; | ||
| 1587 | ; NOTE: MapHandleArray will only access AH on the stack and so the | ||
| 1588 | ; TSTF stack frame will work properly for this procedure. | ||
| 1589 | ; | ||
| 1590 | ; ENTRY: VTFOE frame,EBP,EBX,ESI are on the stack | ||
| 1591 | ; | ||
| 1592 | ;****************************************************************************** | ||
| 1593 | |||
| 1594 | AMC_return_address proc far | ||
| 1595 | |||
| 1596 | ; | ||
| 1597 | ; This will causes an illegal instruction trap and goes into protected | ||
| 1598 | ; mode. The handler will return back to the point right after the | ||
| 1599 | ; 2 bytes ARPL instruction with ring0 stack having and IRETD stack frame | ||
| 1600 | ; | ||
| 1601 | arpl ax, ax | ||
| 1602 | ; | ||
| 1603 | ; In Protected Mode Now | ||
| 1604 | ; | ||
| 1605 | pushad ; saves all regs | ||
| 1606 | mov ax, sp ; saves stack frame address | ||
| 1607 | mov [_regp], ax ; to _regp | ||
| 1608 | |||
| 1609 | mov esi, dword ptr [bp.VTFOE.VMTF_ESP] ; clients's ESP | ||
| 1610 | mov ax, word ptr [bp.VTFOE.VMTF_SS] ; client's SS | ||
| 1611 | xor dx, dx ; AX:DX <-- Seg:Off of Client's Stack | ||
| 1612 | |||
| 1613 | Set_EMM_GDT EMM2_GSEL | ||
| 1614 | mov fs, bx ; FS:SI <-- client's Stack | ||
| 1615 | |||
| 1616 | cld ; forward | ||
| 1617 | ; | ||
| 1618 | ; "pop" back registers on "stack" FS:SI | ||
| 1619 | ; | ||
| 1620 | push fs | ||
| 1621 | pop ds | ||
| 1622 | lodsw | ||
| 1623 | mov es, ax ; DGROUP | ||
| 1624 | lodsw | ||
| 1625 | mov dx, ax ; EMM handle | ||
| 1626 | lodsw ; subfunction code | ||
| 1627 | ; | ||
| 1628 | ; restore mapping context | ||
| 1629 | ; | ||
| 1630 | push ax | ||
| 1631 | |||
| 1632 | push es | ||
| 1633 | pop ds ; DGROUP | ||
| 1634 | get_FRS_Window DI ; ES:DI <-- FRS mapping context regs | ||
| 1635 | push fs | ||
| 1636 | pop ds ; DS:SI <-- client's stack | ||
| 1637 | xor ch, ch | ||
| 1638 | mov cl, ES:[_cntxt_bytes] | ||
| 1639 | shr cx, 1 ; move word | ||
| 1640 | cld | ||
| 1641 | rep movsw | ||
| 1642 | ; | ||
| 1643 | ; map old mapping | ||
| 1644 | ; | ||
| 1645 | lodsb | ||
| 1646 | mov ah, 0 | ||
| 1647 | mov cx, ax ; length | ||
| 1648 | pop ax ; subfunction code | ||
| 1649 | push si | ||
| 1650 | push cx | ||
| 1651 | push bp | ||
| 1652 | mov bp, [_regp] ; setup pushad frame first | ||
| 1653 | push es | ||
| 1654 | pop ds ; DS <-- DGROUP | ||
| 1655 | call MapHandleArray_Entry_2 ; map it | ||
| 1656 | pop bp | ||
| 1657 | pop cx | ||
| 1658 | pop si | ||
| 1659 | shl cx, 2 ; 4 bytes per mapping | ||
| 1660 | release_space_to_stack CX | ||
| 1661 | ; | ||
| 1662 | ; saves CS:IP (BX:CX) on iretd stack frame | ||
| 1663 | ; | ||
| 1664 | push fs | ||
| 1665 | pop ds ; DS <-- Client's Stack | ||
| 1666 | push ax | ||
| 1667 | lodsw | ||
| 1668 | mov word ptr [bp.VTFOE+VMTF_EIP], ax | ||
| 1669 | lodsw | ||
| 1670 | mov word ptr [bp.VTFOE+VMTF_CS], ax | ||
| 1671 | lodsw | ||
| 1672 | mov word ptr [bp.VTFOE+VMTF_EFLAGS], ax | ||
| 1673 | mov word ptr [bp.VTFOE+VMTF_EFLAGShi], PFLAG_VM | ||
| 1674 | pop ax | ||
| 1675 | ; | ||
| 1676 | ; save client's new stack pointer | ||
| 1677 | ; | ||
| 1678 | mov dword ptr [bp.VTFOE.VMTF_ESP], esi | ||
| 1679 | popad | ||
| 1680 | pop esi | ||
| 1681 | pop ebx | ||
| 1682 | pop ebp | ||
| 1683 | add esp, 4 ; discard "error" code | ||
| 1684 | ; | ||
| 1685 | ; set return status | ||
| 1686 | ; | ||
| 1687 | mov ah, OK | ||
| 1688 | |||
| 1689 | iretd | ||
| 1690 | |||
| 1691 | AMC_return_address endp | ||
| 1692 | |||
| 1693 | page | ||
| 1694 | ;****************************************************************************** | ||
| 1695 | ; | ||
| 1696 | ; _MoveExchangeMemory | ||
| 1697 | ; | ||
| 1698 | ; This function (23) will copy or exchange memory between EMM and | ||
| 1699 | ; conventional memory or EMM to EMM. | ||
| 1700 | ; Subfunction 0 is memory copy. Subfunction 1 is exchange. | ||
| 1701 | ; The current mapping context is preserved since the EMM pages are | ||
| 1702 | ; mapped into high memory using VM1s page table. | ||
| 1703 | ; | ||
| 1704 | ; ENTRY: PROTECTED MODE ONLY | ||
| 1705 | ; AL = Subfunction -- 0 = Copy, 1 = Exchange | ||
| 1706 | ; DX = EMM handle | ||
| 1707 | ; REGS on STACK DS:SI = Move/Exchange structure | ||
| 1708 | ; SS:[BP] -> regp stack frame | ||
| 1709 | ; DS = DGROUP | ||
| 1710 | ; | ||
| 1711 | ; EXIT: AL = Status | ||
| 1712 | ; | ||
| 1713 | ; USES: AX, BX, CX, DX, SI, DI | ||
| 1714 | ; | ||
| 1715 | ;============================================================================== | ||
| 1716 | ; | ||
| 1717 | ; ALGORITHM: | ||
| 1718 | ; | ||
| 1719 | ; BEGIN | ||
| 1720 | ; check/validate source/dest and overlay,etc | ||
| 1721 | ; | ||
| 1722 | ; save mapping context of first physical page frame as source page frame | ||
| 1723 | ; save mapping context of second physical page frame as dest page frame | ||
| 1724 | ; | ||
| 1725 | ; /* | ||
| 1726 | ; * setup source and dest memory pointers | ||
| 1727 | ; */ | ||
| 1728 | ; if (source.type == conv.mem) | ||
| 1729 | ; DS:SI = source.initial.segment:source.initial.offset | ||
| 1730 | ; else | ||
| 1731 | ; if (backward.copy) | ||
| 1732 | ; calculate last source emm page and new offset | ||
| 1733 | ; map source.initial.page into source.page.frame | ||
| 1734 | ; DS:SI = segment.of.source.page.frame:source.initial.offset | ||
| 1735 | ; | ||
| 1736 | ; if (dest.type == conv.mem) | ||
| 1737 | ; ES:DI = dest.initial.segment:dest.initial.offset | ||
| 1738 | ; else | ||
| 1739 | ; if (backward.copy) | ||
| 1740 | ; calculate last dest emm page and new offset | ||
| 1741 | ; map dest.initial.page into dest.page.frame | ||
| 1742 | ; ES:DI = segment.of.dest.page.frame:dest.initial.offset | ||
| 1743 | ; | ||
| 1744 | ; /******** | ||
| 1745 | ; * | ||
| 1746 | ; * DS:SI - addresses source data area | ||
| 1747 | ; * ES:DI - addresses dest buffer area | ||
| 1748 | ; * | ||
| 1749 | ; */ | ||
| 1750 | ; | ||
| 1751 | ; for (total.byte.to.process != 0) { | ||
| 1752 | ; /* | ||
| 1753 | ; * find out how many bytes to process (least bytes to process) | ||
| 1754 | ; */ | ||
| 1755 | ; if (source.type == conv.mem) | ||
| 1756 | ; bytes.to.process = 0x4000 - dest.offset | ||
| 1757 | ; else | ||
| 1758 | ; if (dest.type == conv.mem) | ||
| 1759 | ; bytes.to.process = 0x4000 - source.offset | ||
| 1760 | ; else /* emm to emm */ | ||
| 1761 | ; if (backward.copy) | ||
| 1762 | ; bytes.to.process = min(source.offset, dest.offset) + 1 | ||
| 1763 | ; else | ||
| 1764 | ; bytes.to.process = 0x4000 - max(source.offset, dest.offset) | ||
| 1765 | ; | ||
| 1766 | ; /* | ||
| 1767 | ; * adjust the total | ||
| 1768 | ; */ | ||
| 1769 | ; if (bytes.to.process > totol.bytes.to.process) | ||
| 1770 | ; bytes.to.process = totol.bytes.to.process | ||
| 1771 | ; | ||
| 1772 | ; total.bytes.to.process -= bytes.to.process | ||
| 1773 | ; | ||
| 1774 | ; /* | ||
| 1775 | ; * do the processing | ||
| 1776 | ; */ | ||
| 1777 | ; move/exchange bytes.to.process bytes | ||
| 1778 | ; | ||
| 1779 | ; /* | ||
| 1780 | ; * adjust memory pointers and map in new pages if necessary | ||
| 1781 | ; * for the next iternation | ||
| 1782 | ; */ | ||
| 1783 | ; if (total.bytes.to.process != 0) | ||
| 1784 | ; if (source.type == emm) | ||
| 1785 | ; if (SI == 0x4000) | ||
| 1786 | ; /* | ||
| 1787 | ; * forward.copy's index expire | ||
| 1788 | ; */ | ||
| 1789 | ; map next emm source page into source.page.frame | ||
| 1790 | ; SI = 0 | ||
| 1791 | ; if (SI == 0xffff) | ||
| 1792 | ; /* | ||
| 1793 | ; * backward.copy's index expire | ||
| 1794 | ; */ | ||
| 1795 | ; map prev emm source page into source.page.frame | ||
| 1796 | ; SI = 0x3fff | ||
| 1797 | ; else | ||
| 1798 | ; normalize DS:SI | ||
| 1799 | ; | ||
| 1800 | ; if (dest.type == emm) | ||
| 1801 | ; if (DI == 0x4000) | ||
| 1802 | ; /* | ||
| 1803 | ; * forward.copy's index expire | ||
| 1804 | ; */ | ||
| 1805 | ; map next emm dest page into dest.page.frame | ||
| 1806 | ; DI = 0 | ||
| 1807 | ; if (DI == 0xffff) | ||
| 1808 | ; /* | ||
| 1809 | ; * backward.copy's index expire | ||
| 1810 | ; */ | ||
| 1811 | ; map prev emm dest page into dest.page.frame | ||
| 1812 | ; DI = 0x3fff | ||
| 1813 | ; else | ||
| 1814 | ; normalize ES:DI | ||
| 1815 | ; } | ||
| 1816 | ; | ||
| 1817 | ; restore first page frame's mapping context | ||
| 1818 | ; restore second page frame's mapping context | ||
| 1819 | ; END | ||
| 1820 | ; | ||
| 1821 | ;============================================================================== | ||
| 1822 | |||
| 1823 | |||
| 1824 | _MoveExchangeMemory proc near | ||
| 1825 | mov byte ptr [bp.rAX+1], OK ; Assume everything work OK | ||
| 1826 | cld ; Assume forward direction | ||
| 1827 | |||
| 1828 | cmp al, 1 ; Q: Valid subfunction? | ||
| 1829 | ja mem_inv_sub ; N: Error | ||
| 1830 | |||
| 1831 | push ds | ||
| 1832 | pop fs ; fs <-- addresses MEMM's data group | ||
| 1833 | |||
| 1834 | push dx | ||
| 1835 | push cx | ||
| 1836 | push bx | ||
| 1837 | push ax | ||
| 1838 | |||
| 1839 | push bp | ||
| 1840 | mov bp,[_regp] | ||
| 1841 | mov ax, word ptr [bp.rDS] ; DX:AX <-- move/xchg struct | ||
| 1842 | mov dx, word ptr [bp.rSI] | ||
| 1843 | Set_EMM_GDT USER1_GSEL ; use USER1_GSEL since both EMM1_GSEL | ||
| 1844 | ; and EMM2_GSEL will be used | ||
| 1845 | mov ds, bx | ||
| 1846 | xor si, si ; DS:SI <-- Move/Exchange structure | ||
| 1847 | pop bp | ||
| 1848 | pop ax | ||
| 1849 | pop bx | ||
| 1850 | pop cx | ||
| 1851 | pop dx | ||
| 1852 | |||
| 1853 | mov ecx, [si.mem_region_length]; ECX = Length of memory region | ||
| 1854 | or ecx, ecx ; Q: Move 0 bytes? | ||
| 1855 | jz mem_no_error ; Y: Silly! -- Just return | ||
| 1856 | cmp ecx, 0100000h ; Q: Move greater than 1 Meg? | ||
| 1857 | ja mem_inv_region_len ; Y: Error | ||
| 1858 | |||
| 1859 | mov bl, [si.mem_source.mem_memory_type]; Q: Is move Conventional | ||
| 1860 | or bl, [si.mem_dest.mem_memory_type] ; to Conven? | ||
| 1861 | jz mem_conv_to_conv ; Y: Go do it | ||
| 1862 | |||
| 1863 | mov bl, [si.mem_source.mem_memory_type]; Q: Is move EMM | ||
| 1864 | and bl, [si.mem_dest.mem_memory_type] ; to EMM | ||
| 1865 | jz SHORT mem_no_overlap ; N: No overlap | ||
| 1866 | mov bx, [si.mem_source.mem_handle] | ||
| 1867 | cmp bx, [si.mem_dest.mem_handle] ; Q: Same handle? | ||
| 1868 | jnz SHORT mem_no_overlap ; N: No overlap | ||
| 1869 | movzx ebx, [si.mem_source.mem_initial_seg_page] | ||
| 1870 | movzx edx, [si.mem_source.mem_initial_offset] | ||
| 1871 | shl ebx, 14 ; * 4000h | ||
| 1872 | add ebx, edx ; EBX = Source offset within EMM | ||
| 1873 | push ebx ; Save it temporarily | ||
| 1874 | movzx edx, [si.mem_dest.mem_initial_seg_page] | ||
| 1875 | movzx ebx, [si.mem_dest.mem_initial_offset] | ||
| 1876 | shl edx, 14 ; * 4000h | ||
| 1877 | add edx, ebx ; EDX = Dest offset within EMM | ||
| 1878 | pop ebx ; Source offset | ||
| 1879 | sub edx, ebx ; EDX = Source - Destination | ||
| 1880 | jg SHORT mem_dest_gt_source ; Don't negate if Dest > Source | ||
| 1881 | or al, Source_GT_Dest_Flag ; Set flag to note Source > Dest | ||
| 1882 | neg edx ; Absolute value of EDX | ||
| 1883 | mem_dest_gt_source: | ||
| 1884 | cmp edx, ecx ; Q: Is there an overlap? | ||
| 1885 | jae SHORT mem_no_overlap ; N: Continue | ||
| 1886 | test al, 1 ; Q: Is this an exchange? | ||
| 1887 | jnz mem_inv_overlap ; Y: Error -- Cant overlap xchg | ||
| 1888 | mov byte ptr [bp.rAX+1], VALID_OVERLAP ; Assume everything OK but overlap | ||
| 1889 | or al, Overlap_Flag ; N: Note this for later | ||
| 1890 | test al, Source_GT_Dest_Flag ; Q: Is it gonna be backward copy | ||
| 1891 | jnz mem_no_overlap ; N: Continue | ||
| 1892 | or al, Backward_Copy_Flag ; Y: Note for later | ||
| 1893 | std ; Set backword direction | ||
| 1894 | |||
| 1895 | mem_no_overlap: | ||
| 1896 | ; | ||
| 1897 | ; check validility of source | ||
| 1898 | ; | ||
| 1899 | lea di, [si.mem_source] | ||
| 1900 | call validate_for_Move_or_Exchange | ||
| 1901 | or ah, ah | ||
| 1902 | jnz mem_error_exit | ||
| 1903 | ; | ||
| 1904 | ; check validility of dest | ||
| 1905 | ; | ||
| 1906 | lea di, [si.mem_dest] | ||
| 1907 | call validate_for_Move_or_Exchange | ||
| 1908 | or ah, ah | ||
| 1909 | jnz mem_error_exit | ||
| 1910 | |||
| 1911 | or edx, edx ; delayed test for exact move/xchg | ||
| 1912 | je mem_valid_overlap ; WEIRD!!! -- Move to same place! | ||
| 1913 | ; | ||
| 1914 | ; initialize loop | ||
| 1915 | ; | ||
| 1916 | push ds | ||
| 1917 | pop gs | ||
| 1918 | mov bx, si ; GS:BX <-- move/exchange structure | ||
| 1919 | ; | ||
| 1920 | ; save first 2 physical page frames' mapping and use those pages | ||
| 1921 | ; as source and dest physical pages | ||
| 1922 | ; | ||
| 1923 | push fs | ||
| 1924 | pop ds ; DS <-- DGROUP | ||
| 1925 | get_FRS_Window SI | ||
| 1926 | push word ptr [SI] ; save 1st pgae's mapping on stack | ||
| 1927 | push word ptr [SI+2] ; save 2st page's mapping on stack | ||
| 1928 | |||
| 1929 | ; | ||
| 1930 | ; setup dest | ||
| 1931 | ; | ||
| 1932 | mem_set_dest: | ||
| 1933 | cmp gs:[bx.mem_dest.mem_memory_type], 0 ; Q: conv mem ? | ||
| 1934 | jnz mem_map_dest ; N: map in emm page | ||
| 1935 | ; | ||
| 1936 | ; conv memory : setup starting address of dest (always forward) | ||
| 1937 | ; | ||
| 1938 | mov cx, gs:[bx.mem_dest.mem_initial_seg_page] | ||
| 1939 | mov dx, gs:[bx.mem_dest.mem_initial_offset] ; CX:DX <-- dest address | ||
| 1940 | |||
| 1941 | push ax | ||
| 1942 | push bx | ||
| 1943 | mov ax, cx ; AX:DX <-- first byte | ||
| 1944 | Set_EMM_GDT EMM2_GSEL | ||
| 1945 | mov es, bx | ||
| 1946 | xor di, di ; ES:DI <-- dest SelOff | ||
| 1947 | pop bx | ||
| 1948 | pop ax | ||
| 1949 | push 0ffffh ; fake a logical page# | ||
| 1950 | jmp mem_set_source | ||
| 1951 | |||
| 1952 | mem_map_dest: | ||
| 1953 | ; | ||
| 1954 | ; emm memory : find out starting address of dest | ||
| 1955 | ; | ||
| 1956 | mov dx, gs:[bx.mem_dest.mem_initial_seg_page] ; initial logical page# | ||
| 1957 | mov di, gs:[bx.mem_dest.mem_initial_offset] ; initial offset | ||
| 1958 | |||
| 1959 | test al, Backward_Copy_Flag ; Q: Backward copy ? | ||
| 1960 | jz SHORT mem_map_dest_forward ; N: forward | ||
| 1961 | |||
| 1962 | ; | ||
| 1963 | ; backward move : calculate last logical page# and offset | ||
| 1964 | ; | ||
| 1965 | mov ecx, gs:[bx.mem_region_length] | ||
| 1966 | movzx edi, gs:[bx.mem_dest.mem_initial_offset] | ||
| 1967 | dec edi | ||
| 1968 | add ecx, edi | ||
| 1969 | push ecx | ||
| 1970 | and ecx, 00003fffh | ||
| 1971 | mov edi, ecx ; new offset | ||
| 1972 | pop ecx | ||
| 1973 | shr ecx, 14 ; / 16K = # of pages | ||
| 1974 | add dx, cx ; last emm page# | ||
| 1975 | |||
| 1976 | mem_map_dest_forward: | ||
| 1977 | push dx ; put current dest logical page# on stack | ||
| 1978 | ; | ||
| 1979 | ; prepare to map | ||
| 1980 | ; | ||
| 1981 | push ax | ||
| 1982 | push bx | ||
| 1983 | |||
| 1984 | push dx | ||
| 1985 | mov dx, gs:[bx.mem_dest.mem_handle] | ||
| 1986 | Handle2HandlePtr | ||
| 1987 | pop bx | ||
| 1988 | mov ax, 1 ; 2nd page frame | ||
| 1989 | call map_page | ||
| 1990 | jc mem_mapping_error_3_pop ; pop out dest seg_page | ||
| 1991 | |||
| 1992 | ; contruct GDT entry for EMM2_GSEL for ES:0 | ||
| 1993 | ; | ||
| 1994 | mov ax, [PF_Base] | ||
| 1995 | add ax, 0400h ; 2nd page frame segment | ||
| 1996 | xor dx, dx ; offset 0 | ||
| 1997 | Set_EMM_GDT EMM2_GSEL | ||
| 1998 | mov es, bx ; ES:DI <-- dest address | ||
| 1999 | |||
| 2000 | pop bx | ||
| 2001 | pop ax | ||
| 2002 | |||
| 2003 | ; | ||
| 2004 | ; setup source | ||
| 2005 | ; | ||
| 2006 | mem_set_source: | ||
| 2007 | cmp gs:[bx.mem_source.mem_memory_type], 0 ; Q: conv mem ? | ||
| 2008 | jnz mem_map_source ; N: map in emm page | ||
| 2009 | ; | ||
| 2010 | ; conv memory : setup starting address of source (always forward) | ||
| 2011 | ; | ||
| 2012 | mov cx, gs:[bx.mem_source.mem_initial_seg_page] | ||
| 2013 | mov dx, gs:[bx.mem_source.mem_initial_offset] ; CX:DX <-- source address | ||
| 2014 | |||
| 2015 | push ax | ||
| 2016 | push bx | ||
| 2017 | push es | ||
| 2018 | mov ax, cx ; AX:DX <-- first byte | ||
| 2019 | Set_EMM_GDT EMM1_GSEL | ||
| 2020 | mov ds, bx | ||
| 2021 | xor si, si | ||
| 2022 | pop es | ||
| 2023 | pop bx | ||
| 2024 | pop ax | ||
| 2025 | push 0ffffh ; fake a logical page# | ||
| 2026 | jmp short mem_set_done | ||
| 2027 | |||
| 2028 | mem_map_source: | ||
| 2029 | ; | ||
| 2030 | ; emm memory : find out starting address of dest | ||
| 2031 | ; | ||
| 2032 | mov dx, gs:[bx.mem_source.mem_initial_seg_page] ; initial logical page# | ||
| 2033 | mov si, gs:[bx.mem_source.mem_initial_offset] ; inital offset | ||
| 2034 | |||
| 2035 | test al, Backward_Copy_Flag ; Q: Backward copy ? | ||
| 2036 | jz SHORT mem_map_source_forward ; N: forward | ||
| 2037 | |||
| 2038 | ; | ||
| 2039 | ; backward move : calculate last logical page# and offset | ||
| 2040 | ; | ||
| 2041 | mov ecx, gs:[bx.mem_region_length] | ||
| 2042 | movzx esi, gs:[bx.mem_source.mem_initial_offset] | ||
| 2043 | dec esi | ||
| 2044 | add ecx, esi | ||
| 2045 | push ecx | ||
| 2046 | and ecx, 00003fffh | ||
| 2047 | mov esi, ecx ; new offset | ||
| 2048 | pop ecx | ||
| 2049 | shr ecx, 14 ; / 16K = # of pages | ||
| 2050 | add dx, cx ; last emm page# | ||
| 2051 | |||
| 2052 | mem_map_source_forward: | ||
| 2053 | push dx ; put current source logical page# on stack | ||
| 2054 | ; | ||
| 2055 | ; prepare to map | ||
| 2056 | ; | ||
| 2057 | push ax | ||
| 2058 | push bx | ||
| 2059 | |||
| 2060 | push dx | ||
| 2061 | mov dx, gs:[bx.mem_source.mem_handle] | ||
| 2062 | Handle2HandlePtr | ||
| 2063 | pop bx | ||
| 2064 | mov ax, 0 ; 1st page frame | ||
| 2065 | call map_page | ||
| 2066 | jc mem_mapping_error_4_pop ; pop out dest and source seg_page | ||
| 2067 | |||
| 2068 | ; contruct GDT entry for EMM1_GSEL for DS:0 | ||
| 2069 | ; | ||
| 2070 | mov ax, [PF_Base] ; 1st page frame segment | ||
| 2071 | xor dx, dx ; offset 0 | ||
| 2072 | push es | ||
| 2073 | Set_EMM_GDT EMM1_GSEL | ||
| 2074 | pop es ; ES:0 <-- GDT | ||
| 2075 | mov ds, bx ; ES:DI <-- dest address | ||
| 2076 | |||
| 2077 | pop bx | ||
| 2078 | pop ax | ||
| 2079 | |||
| 2080 | ; DS:SI <-- source address | ||
| 2081 | ; ES:DI <-- dest address | ||
| 2082 | |||
| 2083 | mem_set_done: | ||
| 2084 | mov edx, gs:[bx.mem_region_length] ; total length to move/xchg | ||
| 2085 | |||
| 2086 | ; | ||
| 2087 | ; main move/exchange loop | ||
| 2088 | ; | ||
| 2089 | mem_loop: | ||
| 2090 | mov ecx, cr3 | ||
| 2091 | mov cr3, ecx ; flush TLB after each map loop | ||
| 2092 | |||
| 2093 | mov ecx, 4000h ; maximum length to move/xchg | ||
| 2094 | ; in one mapping (<16K) | ||
| 2095 | cmp gs:[bx.mem_source.mem_memory_type], 0 ; Q: conv mem ? | ||
| 2096 | jnz mem_source_is_emm ; N: check dest | ||
| 2097 | sub cx, di ; CX <-- length to move/xchg | ||
| 2098 | jmp short mem_calculate_length | ||
| 2099 | mem_source_is_emm: | ||
| 2100 | cmp gs:[bx.mem_dest.mem_memory_type], 0 ; Q: conv mem ? | ||
| 2101 | jnz mem_both_are_emm ; N: find out which | ||
| 2102 | ; emm has less | ||
| 2103 | ; to move/exchange | ||
| 2104 | sub cx, si ; CX <-- length to move/xchg | ||
| 2105 | jmp short mem_calculate_length | ||
| 2106 | mem_both_are_emm: | ||
| 2107 | test al, Backward_Copy_Flag ; Q:backward copy ? | ||
| 2108 | jz SHORT mem_2_emm_forward ; N:forward | ||
| 2109 | mov cx, si | ||
| 2110 | inc cx | ||
| 2111 | cmp si, di ; Q:si<di ? (min(si,di)) | ||
| 2112 | jb short mem_calculate_length ; Y: use si | ||
| 2113 | mov cx, di ; N: use di | ||
| 2114 | inc cx | ||
| 2115 | jmp short mem_calculate_length | ||
| 2116 | |||
| 2117 | mem_2_emm_forward: | ||
| 2118 | cmp si, di ; Q:si>di ? (max(si,di)) | ||
| 2119 | ja mem_si_gt_di ; Y: use si | ||
| 2120 | sub cx, di ; N: use di | ||
| 2121 | jmp short mem_calculate_length | ||
| 2122 | mem_si_gt_di: | ||
| 2123 | sub cx, si ; si>di | ||
| 2124 | |||
| 2125 | mem_calculate_length: | ||
| 2126 | cmp ecx, edx ; Q: bytes in this batch > total | ||
| 2127 | jbe mem_do_move_xchg ; N: go ahead to move/xchg | ||
| 2128 | mov ecx, edx ; Y: use total instead | ||
| 2129 | |||
| 2130 | ; | ||
| 2131 | ; move/xchg loop | ||
| 2132 | ; | ||
| 2133 | mem_do_move_xchg: | ||
| 2134 | sub edx, ecx ; Adjust total first | ||
| 2135 | |||
| 2136 | test al, 1 ; Q: Is this an exchange? | ||
| 2137 | jnz SHORT mem_exchange ; Y: Do it | ||
| 2138 | test al, Backward_Copy_Flag ; N: Q:Is this backward copy ? | ||
| 2139 | jz SHORT mem_move_forward ; N: forward | ||
| 2140 | ; | ||
| 2141 | ; memory move backward | ||
| 2142 | ; | ||
| 2143 | rep movsb | ||
| 2144 | jmp mem_next_round | ||
| 2145 | ; | ||
| 2146 | ; memory move forward | ||
| 2147 | ; | ||
| 2148 | mem_move_forward: | ||
| 2149 | push eax | ||
| 2150 | mov eax, ecx | ||
| 2151 | shr ecx, 2 ; ECX = # DWORDS to copy | ||
| 2152 | rep movsd ; Move the DWORDS | ||
| 2153 | mov ecx, eax | ||
| 2154 | and ecx, 00000003h ; ECX = # BYTES left to copy | ||
| 2155 | rep movsb ; Move the BYTES | ||
| 2156 | pop eax | ||
| 2157 | jmp short mem_next_round | ||
| 2158 | ; | ||
| 2159 | ; momory exchange | ||
| 2160 | ; | ||
| 2161 | mem_exchange: | ||
| 2162 | push dx | ||
| 2163 | push ax | ||
| 2164 | push bx | ||
| 2165 | push ecx ; Save total # bytes on stack | ||
| 2166 | shr ecx, 2 ; ECX = # DWORDS to exchange | ||
| 2167 | jecxz mem_xchg_bytes ; Exit if no DWORDS left | ||
| 2168 | mov dx, 4 ; Size of DWORD | ||
| 2169 | mem_xchg_dword_loop: | ||
| 2170 | mov eax, [si] | ||
| 2171 | mov ebx, es:[di] | ||
| 2172 | mov es:[di], eax | ||
| 2173 | mov [si], ebx | ||
| 2174 | add si, dx | ||
| 2175 | add di, dx | ||
| 2176 | loop mem_xchg_dword_loop ; Loop until all DWORDS exchanged | ||
| 2177 | mem_xchg_bytes: | ||
| 2178 | pop ecx | ||
| 2179 | and ecx, 00000003h ; ECX = # BYTES left to exchange | ||
| 2180 | jecxz mem_xchg_done ; Exit if no DWORDS left | ||
| 2181 | mem_xchg_byte_loop: | ||
| 2182 | mov al, [si] | ||
| 2183 | mov bl, es:[di] | ||
| 2184 | mov es:[di], al | ||
| 2185 | mov [si], bl | ||
| 2186 | inc si | ||
| 2187 | inc di | ||
| 2188 | loop mem_xchg_byte_loop ; Loop until all BYTES exchanged | ||
| 2189 | mem_xchg_done: | ||
| 2190 | pop bx | ||
| 2191 | pop ax | ||
| 2192 | pop dx ; DONE!!!! | ||
| 2193 | |||
| 2194 | ; | ||
| 2195 | ; prepare for next iteration | ||
| 2196 | ; | ||
| 2197 | mem_next_round: | ||
| 2198 | ; | ||
| 2199 | ; get source and dest's current mapped logical page | ||
| 2200 | ; from stack | ||
| 2201 | ; | ||
| 2202 | pop cx ; source logical page# | ||
| 2203 | shl ecx, 16 ; put in high word | ||
| 2204 | pop cx ; dest logical page# | ||
| 2205 | |||
| 2206 | or edx, edx ; Q: all done ? | ||
| 2207 | jz mem_exit ; Y: restore context first | ||
| 2208 | |||
| 2209 | ; fix dest addresses | ||
| 2210 | ; | ||
| 2211 | cmp gs:[bx.mem_dest.mem_memory_type], 0 ; Q: conv mem ? | ||
| 2212 | jnz mem_map_next_dest ; N: map next page | ||
| 2213 | normalize ES,DI | ||
| 2214 | jmp mem_check_source | ||
| 2215 | |||
| 2216 | mem_map_next_dest: | ||
| 2217 | cmp di, 4000h ; Q: di expires (forward)? | ||
| 2218 | je short mem_map_next_dest_forward ; Y: | ||
| 2219 | cmp di, 0ffffh ; Q: di expires (backward) ? | ||
| 2220 | jne short mem_check_source ; N: go check source | ||
| 2221 | |||
| 2222 | mov di, 3fffh ; set di for next round | ||
| 2223 | dec cx ; next logical page | ||
| 2224 | jmp SHORT mem_map_next_dest_do_map | ||
| 2225 | |||
| 2226 | mem_map_next_dest_forward: | ||
| 2227 | xor di, di ; clear di for next round | ||
| 2228 | inc cx ; next logical page | ||
| 2229 | |||
| 2230 | ; | ||
| 2231 | ; map in the next dest page | ||
| 2232 | ; | ||
| 2233 | mem_map_next_dest_do_map: | ||
| 2234 | push dx | ||
| 2235 | push ax | ||
| 2236 | push bx | ||
| 2237 | push ecx | ||
| 2238 | push ds | ||
| 2239 | push fs | ||
| 2240 | pop ds | ||
| 2241 | mov dx, gs:[bx.mem_dest.mem_handle] | ||
| 2242 | Handle2HandlePtr | ||
| 2243 | mov ax, 1 ; 2nd page frame | ||
| 2244 | mov bx, cx | ||
| 2245 | call map_page | ||
| 2246 | pop ds | ||
| 2247 | pop ecx | ||
| 2248 | pop bx | ||
| 2249 | pop ax | ||
| 2250 | pop dx | ||
| 2251 | jc mem_mapping_error | ||
| 2252 | |||
| 2253 | ; | ||
| 2254 | ; fix source addresses | ||
| 2255 | ; | ||
| 2256 | mem_check_source: | ||
| 2257 | ror ecx, 16 ; get source log page in low word | ||
| 2258 | cmp gs:[bx.mem_source.mem_memory_type], 0 ; Q: conv mem ? | ||
| 2259 | jnz mem_map_next_source ; N: map next page | ||
| 2260 | normalize DS,SI | ||
| 2261 | jmp mem_check_done | ||
| 2262 | |||
| 2263 | mem_map_next_source: | ||
| 2264 | cmp si, 4000h ; Q: si expires (forward)? | ||
| 2265 | je short mem_map_next_source_forward ; Y: | ||
| 2266 | cmp si, 0ffffh ; Q: si expires (backward) ? | ||
| 2267 | jne short mem_check_done ; N: all done | ||
| 2268 | |||
| 2269 | mov si, 3fffh ; set si for next round | ||
| 2270 | dec cx ; next logical page | ||
| 2271 | jmp SHORT mem_map_next_source_do_map | ||
| 2272 | |||
| 2273 | mem_map_next_source_forward: | ||
| 2274 | xor si, si ; clear si for next round | ||
| 2275 | inc cx ; next logical page | ||
| 2276 | |||
| 2277 | ; | ||
| 2278 | ; map in the next source page | ||
| 2279 | ; | ||
| 2280 | mem_map_next_source_do_map: | ||
| 2281 | push dx | ||
| 2282 | push ax | ||
| 2283 | push bx | ||
| 2284 | push ecx | ||
| 2285 | push ds | ||
| 2286 | push fs | ||
| 2287 | pop ds | ||
| 2288 | mov dx, gs:[bx.mem_source.mem_handle] | ||
| 2289 | Handle2HandlePtr | ||
| 2290 | mov ax, 0 ; 1st page frame | ||
| 2291 | mov bx, cx | ||
| 2292 | call map_page | ||
| 2293 | pop ds | ||
| 2294 | pop ecx | ||
| 2295 | pop bx | ||
| 2296 | pop ax | ||
| 2297 | pop dx | ||
| 2298 | jc mem_mapping_error | ||
| 2299 | ; | ||
| 2300 | ; push back the logical pages on stack for | ||
| 2301 | ; next iternation : dest first, then source | ||
| 2302 | ; | ||
| 2303 | mem_check_done: | ||
| 2304 | ror ecx, 16 | ||
| 2305 | push cx | ||
| 2306 | ror ecx, 16 | ||
| 2307 | push cx | ||
| 2308 | jmp mem_loop | ||
| 2309 | |||
| 2310 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 2311 | ; | ||
| 2312 | ; conv to conv | ||
| 2313 | ; | ||
| 2314 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 2315 | mem_conv_to_conv: | ||
| 2316 | ; | ||
| 2317 | ; check validility of source | ||
| 2318 | ; | ||
| 2319 | lea di, [si.mem_source] | ||
| 2320 | call validate_for_Move_or_Exchange | ||
| 2321 | or ah, ah | ||
| 2322 | jnz mem_error_exit | ||
| 2323 | ; | ||
| 2324 | ; check validility of dest | ||
| 2325 | ; | ||
| 2326 | lea di, [si.mem_dest] | ||
| 2327 | call validate_for_Move_or_Exchange | ||
| 2328 | or ah, ah | ||
| 2329 | jnz mem_error_exit | ||
| 2330 | |||
| 2331 | push ax ; save subfunction | ||
| 2332 | push [si.mem_region_length] ; save length | ||
| 2333 | |||
| 2334 | movzx eax, [si.mem_dest.mem_initial_seg_page] | ||
| 2335 | movzx edx, [si.mem_dest.mem_initial_offset] | ||
| 2336 | mov edi, eax | ||
| 2337 | shl edi, 4 | ||
| 2338 | add edi, edx ; EDI <-- dest linear addr | ||
| 2339 | Set_EMM_GDT EMM2_GSEL | ||
| 2340 | Set_Page_Gran EMM2_GSEL | ||
| 2341 | push bx ; save dest GDT selector | ||
| 2342 | |||
| 2343 | movzx eax, [si.mem_source.mem_initial_seg_page] | ||
| 2344 | movzx edx, [si.mem_source.mem_initial_offset] | ||
| 2345 | mov esi, eax | ||
| 2346 | shl esi, 4 | ||
| 2347 | add esi, edx ; ESI <-- source linear addr | ||
| 2348 | Set_EMM_GDT EMM1_GSEL | ||
| 2349 | Set_Page_Gran EMM1_GSEL | ||
| 2350 | mov ds, bx | ||
| 2351 | |||
| 2352 | pop es ; recover dest GDT sel | ||
| 2353 | pop ecx ; recover length | ||
| 2354 | pop ax ; recover subfunction | ||
| 2355 | ; | ||
| 2356 | ; test for overlapping transfer | ||
| 2357 | ; | ||
| 2358 | mov byte ptr [bp.rAX+1], VALID_OVERLAP ; assume valid overlap | ||
| 2359 | sub edi, esi ; EDI = Source - Destination | ||
| 2360 | jg SHORT mem_dest_gt_source_2 ; Don't negate if Dest > Source | ||
| 2361 | or al, Source_GT_Dest_Flag ; Set flag to note Source > Dest | ||
| 2362 | neg edi ; Absolute value of EDI | ||
| 2363 | mem_dest_gt_source_2: | ||
| 2364 | mov ebx, edi ; Use EBX instead | ||
| 2365 | cmp ebx, ecx ; Q: Is there an overlap? | ||
| 2366 | jae SHORT mem_no_overlap_2 ; N: Continue | ||
| 2367 | test al, 1 ; Q: Is this an exchange? | ||
| 2368 | jnz mem_inv_overlap ; Y: Error -- Cant overlap xchg | ||
| 2369 | or al, Overlap_Flag ; N: Note this for later | ||
| 2370 | test al, Source_GT_Dest_Flag ; Q: Is it gonna be backward copy | ||
| 2371 | jnz mem_no_overlap_2 ; N: Continue | ||
| 2372 | or al, Backward_Copy_Flag ; Y: Note for later | ||
| 2373 | |||
| 2374 | mov edx, (not 1)+1 ; increment value of -1 (2's compliment of 4) | ||
| 2375 | mov esi, ecx ; Fix ESI and EDI for reverse copy | ||
| 2376 | dec esi | ||
| 2377 | mov edi, esi | ||
| 2378 | jmp short mem_conv_copy | ||
| 2379 | |||
| 2380 | mem_no_overlap_2: | ||
| 2381 | mov byte ptr [ebp.rAX+1], OK ; Everything worked OK | ||
| 2382 | mov edx, 1 ; increment value of 1 | ||
| 2383 | xor esi, esi ; DS:ESI <-- source addr | ||
| 2384 | xor edi, edi ; ES:EDI <-- dest addr | ||
| 2385 | |||
| 2386 | test al, 1 ; Q:copy ? | ||
| 2387 | jnz mem_conv_xchg ; N:go do exchange | ||
| 2388 | |||
| 2389 | mem_conv_copy: | ||
| 2390 | or ebx, ebx | ||
| 2391 | je mem_valid_overlap ; WEIRD!!! -- Move to same place! | ||
| 2392 | |||
| 2393 | jecxz mem_conv_done | ||
| 2394 | mem_conv_copy_loop: | ||
| 2395 | mov bl, [esi] | ||
| 2396 | mov es:[edi], bl | ||
| 2397 | add esi, edx | ||
| 2398 | add edi, edx | ||
| 2399 | dec ecx | ||
| 2400 | jnz mem_conv_copy_loop | ||
| 2401 | jmp mem_conv_done ; DONE!!!! | ||
| 2402 | |||
| 2403 | mem_conv_xchg: | ||
| 2404 | jecxz mem_conv_done | ||
| 2405 | mem_conv_xchg_loop: | ||
| 2406 | mov al, [esi] | ||
| 2407 | mov bl, es:[edi] | ||
| 2408 | mov es:[edi], al | ||
| 2409 | mov [esi], bl | ||
| 2410 | inc esi | ||
| 2411 | inc edi | ||
| 2412 | dec ecx | ||
| 2413 | jnz mem_conv_xchg_loop ; Loop until all BYTES exchanged | ||
| 2414 | mem_conv_done: | ||
| 2415 | Set_Byte_Gran EMM1_GSEL ; make sure EMM1_GSEL and | ||
| 2416 | Set_Byte_Gran EMM2_GSEL ; EMM2_GSEL are Byte Granulated | ||
| 2417 | ret | ||
| 2418 | |||
| 2419 | mem_error_exit: | ||
| 2420 | cld | ||
| 2421 | mov byte ptr [bp.rAX+1], ah ; error code already set in ah | ||
| 2422 | ret | ||
| 2423 | mem_valid_overlap: | ||
| 2424 | mov byte ptr [bp.rAX+1], VALID_OVERLAP | ||
| 2425 | ret | ||
| 2426 | mem_no_error: | ||
| 2427 | mov byte ptr [bp.rAX+1], OK | ||
| 2428 | ret | ||
| 2429 | |||
| 2430 | mem_inv_sub: | ||
| 2431 | mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION | ||
| 2432 | ret | ||
| 2433 | mem_inv_region_len: | ||
| 2434 | mov byte ptr [bp.rAX+1], INVALID_REGION_LENGTH | ||
| 2435 | ret | ||
| 2436 | mem_bad_memory_types: | ||
| 2437 | mov byte ptr [bp.rAX+1], INVALID_MEMORY_TYPE | ||
| 2438 | ret | ||
| 2439 | mem_inv_overlap: | ||
| 2440 | mov byte ptr [bp.rAX+1], OVERLAPPING_EXCHANGE | ||
| 2441 | ret | ||
| 2442 | ; | ||
| 2443 | ; discard old ax,bx,source seg_page#,dest seg_page# | ||
| 2444 | ; | ||
| 2445 | mem_mapping_error_4_pop: | ||
| 2446 | pop bx | ||
| 2447 | mem_mapping_error_3_pop: | ||
| 2448 | pop bx | ||
| 2449 | pop bx | ||
| 2450 | pop bx | ||
| 2451 | mem_mapping_error: | ||
| 2452 | mov eax, cr3 ; Always clear TLB, we may have | ||
| 2453 | mov cr3, eax ; mapped pages before an error | ||
| 2454 | ; | ||
| 2455 | ; all done, need to restore context of physical page frames | ||
| 2456 | ; | ||
| 2457 | mem_exit: | ||
| 2458 | push fs ; get DGROUP back into DS | ||
| 2459 | pop ds | ||
| 2460 | get_FRS_Window BX | ||
| 2461 | pop word ptr [bx+2] | ||
| 2462 | pop word ptr [bx] | ||
| 2463 | cld ; string forward again | ||
| 2464 | jmp _set_windows ; remap all pages | ||
| 2465 | |||
| 2466 | _MoveExchangeMemory endp | ||
| 2467 | |||
| 2468 | |||
| 2469 | ;****************************************************************************** | ||
| 2470 | ; | ||
| 2471 | ; validate_for_Move_Or_Exchange | ||
| 2472 | ; | ||
| 2473 | ; This procedure is called by _MoveExchangeMemory to validate | ||
| 2474 | ; varies parameter on the memeory descriptor structure. | ||
| 2475 | ; It is called once for the source and once for the | ||
| 2476 | ; destination memory descriptor structures. | ||
| 2477 | ; | ||
| 2478 | ; ENTRY: | ||
| 2479 | ; CX = move length | ||
| 2480 | ; DS:DI = Move/Exchange memory descriptor data structure (source or dest) | ||
| 2481 | ; FS = MEMM's data segment | ||
| 2482 | ; EXIT: | ||
| 2483 | ; AH = Status (0 = No error) -- AL is preserved | ||
| 2484 | ; | ||
| 2485 | ; USES: | ||
| 2486 | ; DI, Flags | ||
| 2487 | ; AL and all other registers are preserved | ||
| 2488 | ; | ||
| 2489 | ;============================================================================== | ||
| 2490 | |||
| 2491 | validate_for_Move_Or_Exchange PROC NEAR | ||
| 2492 | |||
| 2493 | push edx ; Used as temporary variable | ||
| 2494 | push eax | ||
| 2495 | |||
| 2496 | mov dl, [di.mem_memory_type] | ||
| 2497 | or dl, dl ; Q: Conventional memory? | ||
| 2498 | jz ME_Map_Conventional ; Y: Nothing to map | ||
| 2499 | cmp dl, 1 ; Q: Expanded memory? | ||
| 2500 | jne ME_Map_Inv_Mem ; N: Invalid memory type | ||
| 2501 | ; Y: EMM memory -- Must map it | ||
| 2502 | mov dx, [di.mem_handle] ; Get the handle | ||
| 2503 | |||
| 2504 | push ds ; validate_handle expect DS | ||
| 2505 | push fs ; points to dgroup | ||
| 2506 | pop ds | ||
| 2507 | Validate_Handle ME_Map_Inv_Handle ; check it | ||
| 2508 | pop ds | ||
| 2509 | |||
| 2510 | xchg bx, dx | ||
| 2511 | mov ax, fs:[bx.ht_count] ; EAX = # pages in handle | ||
| 2512 | xchg bx, dx | ||
| 2513 | cmp ax,[di.mem_initial_seg_page];Q: Is initial page in range | ||
| 2514 | jbe ME_Map_Invalid_log_page ; N: Error | ||
| 2515 | cmp [di.mem_initial_offset], 04000h; Q: Is offset unreasonable? | ||
| 2516 | jae ME_Map_Invalid_Offset ; Y: Error | ||
| 2517 | |||
| 2518 | movzx edx, [di.mem_initial_offset] | ||
| 2519 | add edx, ecx | ||
| 2520 | add edx, 16 * 1024 - 1 ; round up to nearest emm page boundary | ||
| 2521 | shr edx, 14 ; / 16K = # of emm pages | ||
| 2522 | add dx, [di.mem_initial_seg_page] ; last emm page of move/exchange | ||
| 2523 | cmp dx, ax | ||
| 2524 | ja ME_Map_Not_Enough_EMM ;Q: Is last page in range | ||
| 2525 | jmp short ME_Map_OK ; N: error | ||
| 2526 | |||
| 2527 | ME_Map_Conventional: | ||
| 2528 | movzx edx, word ptr [di.mem_initial_seg_page] | ||
| 2529 | shl edx, 4 | ||
| 2530 | movzx edi, word ptr [di.mem_initial_offset] | ||
| 2531 | add edx, edi ; EDX --> Conven mem to move/exch | ||
| 2532 | mov edi, edx ; Use EDI for test | ||
| 2533 | add edi, ecx ; EDI = Base + Move length | ||
| 2534 | cmp edi, 100000h ; Q: Is there wraparound? | ||
| 2535 | jae SHORT ME_Map_Inv_Wraparound ; Y: Error | ||
| 2536 | cmp fs:[_page_frame_pages], 0 ; Is there a page frame? | ||
| 2537 | je short No_EMM_Overlap ; no, no problem | ||
| 2538 | cmp edi, 0E0000h ; Q: Is move ABOVE EMM area? | ||
| 2539 | jae SHORT No_EMM_Overlap ; Y: That's not a problem | ||
| 2540 | movzx eax, fs:[PF_Base] ; Where page frame starts | ||
| 2541 | shl eax, 4 | ||
| 2542 | cmp edi, eax ; Q: Does move run into EMM area? | ||
| 2543 | ja SHORT ME_Map_Inv_Overlap ; Y: Error | ||
| 2544 | No_EMM_Overlap: | ||
| 2545 | ; N: Everything is okie dokie | ||
| 2546 | ME_Map_OK: | ||
| 2547 | pop eax | ||
| 2548 | pop edx | ||
| 2549 | mov ah, OK | ||
| 2550 | ret | ||
| 2551 | |||
| 2552 | ME_Map_Inv_Mem: | ||
| 2553 | pop eax | ||
| 2554 | pop edx | ||
| 2555 | mov ah, INVALID_MEMORY_TYPE | ||
| 2556 | ret | ||
| 2557 | |||
| 2558 | ME_Map_Inv_Handle: | ||
| 2559 | pop ds | ||
| 2560 | pop eax | ||
| 2561 | pop edx | ||
| 2562 | mov ah, INVALID_HANDLE | ||
| 2563 | ret | ||
| 2564 | |||
| 2565 | ME_Map_Invalid_log_page: | ||
| 2566 | pop eax | ||
| 2567 | pop edx | ||
| 2568 | mov ah, LOG_PAGE_RANGE | ||
| 2569 | ret | ||
| 2570 | |||
| 2571 | ME_Map_Invalid_Offset: | ||
| 2572 | pop eax | ||
| 2573 | pop edx | ||
| 2574 | mov ah, INVALID_OFFSET | ||
| 2575 | ret | ||
| 2576 | |||
| 2577 | ME_Map_Not_Enough_EMM: | ||
| 2578 | pop eax | ||
| 2579 | pop edx | ||
| 2580 | mov ah, INSUFFICIENT_EMM_PAGES | ||
| 2581 | ret | ||
| 2582 | |||
| 2583 | ME_Map_Inv_Overlap: | ||
| 2584 | pop eax | ||
| 2585 | pop edx | ||
| 2586 | mov ah, CONVENTIONAL_EMM_OVERLAP | ||
| 2587 | ret | ||
| 2588 | |||
| 2589 | ME_Map_Inv_Wraparound: | ||
| 2590 | pop eax | ||
| 2591 | pop edx | ||
| 2592 | mov ah, INVALID_WRAPAROUND | ||
| 2593 | ret | ||
| 2594 | |||
| 2595 | validate_for_Move_Or_Exchange ENDP | ||
| 2596 | |||
| 2597 | |||
| 2598 | page | ||
| 2599 | ;*********************************************** | ||
| 2600 | ; | ||
| 2601 | ; _AlternateMapRegisterSet - handle alternative register sets | ||
| 2602 | ; | ||
| 2603 | ; This routine switches the current register set or stores | ||
| 2604 | ; the current page mapping context to an external save area and/or | ||
| 2605 | ; restores the current page mapping context from an external save area. | ||
| 2606 | ; | ||
| 2607 | ; ENTRY: PROTECTED MODE ONLY | ||
| 2608 | ; AH = 5Bh = Alternate Map Register Set function | ||
| 2609 | ; AL = SUBFUNCTION CODE | ||
| 2610 | ; AL = 0 => Get Alternate Map Register Set | ||
| 2611 | ; AL = 1 => Set Alternate Map Register Set | ||
| 2612 | ; AL = 2 => Get and Set Alternate Map Register Set | ||
| 2613 | ; AL = 3 => Get Alternate Map Save Array size | ||
| 2614 | ; AL = 4 => Allocate Alternate Map Register Set | ||
| 2615 | ; AL = 5 => Deallocate Alternate Map Register Set | ||
| 2616 | ; AL = 6 => Enable DMA on Alternate Map Register Set | ||
| 2617 | ; AL = 7 => Disable DMA on Alternate Map Register Set | ||
| 2618 | ; See sub-functions for individual ENTRY registers | ||
| 2619 | ; SS:[EBP] -> regp stack frame | ||
| 2620 | ; DS = DGROUP | ||
| 2621 | ; | ||
| 2622 | ; EXIT: from individual sub-function or error with | ||
| 2623 | ; AH = INVALID_SUBFUNCTION | ||
| 2624 | ; | ||
| 2625 | ; USED: EAX,ESI | ||
| 2626 | ; | ||
| 2627 | ;*********************************************** | ||
| 2628 | Dword_Align _TEXT | ||
| 2629 | _AlternateMapRegisterSet proc near | ||
| 2630 | cmp [_OSEnabled], OS_DISABLED | ||
| 2631 | jae short AMRS_NotAllowed ; Disabled by OS | ||
| 2632 | cmp al, 08h ; Valid sub-function? | ||
| 2633 | ja short AMRS_invalid | ||
| 2634 | cld ; Done for all sub-functions | ||
| 2635 | mov byte ptr [bp.rAX+1], OK ; Assume success! | ||
| 2636 | movzx esi, al ; get offset to function dispatch | ||
| 2637 | shl si, 1 | ||
| 2638 | jmp CS:AMRS_map[si] ; go to relevant sub-function | ||
| 2639 | ; Return directly or to AMRS_exit... | ||
| 2640 | AMRS_exit: ; Exit with AH already set | ||
| 2641 | ret | ||
| 2642 | |||
| 2643 | AMRS_NotAllowed: | ||
| 2644 | mov byte ptr [bp.rAX+1], ACCESS_DENIED | ||
| 2645 | ret | ||
| 2646 | |||
| 2647 | AMRS_invalid: | ||
| 2648 | mov byte ptr [bp.rAX+1], INVALID_SUBFUNCTION | ||
| 2649 | ret ; Error return! | ||
| 2650 | |||
| 2651 | AMRS_bad_src: | ||
| 2652 | mov byte ptr [bp.rAX+1], SOURCE_CORRUPTED | ||
| 2653 | ret ; Error return! | ||
| 2654 | |||
| 2655 | AMRS_noDMA: | ||
| 2656 | mov byte ptr [bp.rAX+1], FRSET_NO_DMA | ||
| 2657 | ret ; Error return! | ||
| 2658 | |||
| 2659 | Dword_Align _TEXT | ||
| 2660 | AMRS_map dw _TEXT:AMRS_get | ||
| 2661 | dw _TEXT:AMRS_set | ||
| 2662 | dw _TEXT:AMRS_size | ||
| 2663 | dw _TEXT:AMRS_allocate | ||
| 2664 | dw _TEXT:AMRS_deallocate | ||
| 2665 | ; For now... | ||
| 2666 | dw _TEXT:AMRS_noDMA ; AMRS_DMAallocate | ||
| 2667 | dw _TEXT:AMRS_noDMA ; AMRS_DMAassign | ||
| 2668 | dw _TEXT:AMRS_noDMA ; AMRS_DMAdeassign | ||
| 2669 | dw _TEXT:AMRS_noDMA ; AMRS_DMAfree | ||
| 2670 | |||
| 2671 | page | ||
| 2672 | ;*********************************************** | ||
| 2673 | ; | ||
| 2674 | ; AMRS_get - get the current 'fast' register set | ||
| 2675 | ; | ||
| 2676 | ; ENTRY: on stack | ||
| 2677 | ; SS:[EBP] -> regp stack frame | ||
| 2678 | ; DS = DGROUP | ||
| 2679 | ; | ||
| 2680 | ; EXIT: on stack | ||
| 2681 | ; BL = register set number, | ||
| 2682 | ; state stored in client's buffer if BL == 0 | ||
| 2683 | ; ES:SI set to point to client's buffer | ||
| 2684 | ; return code set on stack | ||
| 2685 | ; | ||
| 2686 | ; USED: EAX, EBX | ||
| 2687 | ; | ||
| 2688 | ; DESCRIPTION: This function returns the current register set number. | ||
| 2689 | ; If it is zero, it returns the save area previously specified | ||
| 2690 | ; | ||
| 2691 | ;----------------------------------------------- | ||
| 2692 | Dword_Align _TEXT | ||
| 2693 | AMRS_get: | ||
| 2694 | mov al, [CurRegSetn] ; Get current set number | ||
| 2695 | mov byte ptr [bp.rBX], al ; to be picked up later | ||
| 2696 | or al, al | ||
| 2697 | jz short AMRS_get0 | ||
| 2698 | ret ; non-zero - all done | ||
| 2699 | AMRS_get0: ; Echo save area address | ||
| 2700 | movzx eax, [EMM_savES] ; saved ES for reg set 0 | ||
| 2701 | mov word ptr [bp.rES], ax | ||
| 2702 | movzx edi, [EMM_savDI] ; saved DI for reg set 0 | ||
| 2703 | mov word ptr [bp.rDI], di | ||
| 2704 | or ax, ax | ||
| 2705 | jnz short AMRS_get2 ; got dest addr | ||
| 2706 | or di, di | ||
| 2707 | jz short AMRS_get1 ; not specified yet | ||
| 2708 | AMRS_get2: | ||
| 2709 | xor dx, dx | ||
| 2710 | Set_EMM_GDT EMM1_GSEL | ||
| 2711 | mov es, bx ; ES:DI <-- temp store | ||
| 2712 | Get_FRS_window SI ; Get pointer to current window | ||
| 2713 | movzx eax, [_cntxt_pages] ; how many pages | ||
| 2714 | stosw ; save size | ||
| 2715 | mov ecx, eax | ||
| 2716 | shr ecx, 1 ; convert to dwords | ||
| 2717 | rep movsd ; save the map | ||
| 2718 | AMRS_get1: | ||
| 2719 | ret | ||
| 2720 | |||
| 2721 | page | ||
| 2722 | ;*********************************************** | ||
| 2723 | ; | ||
| 2724 | ; AMRS_set - set the current 'fast' register set | ||
| 2725 | ; | ||
| 2726 | ; ENTRY: BL = register set number | ||
| 2727 | ; on stack | ||
| 2728 | ; if BL == 0 | ||
| 2729 | ; ES:DI -> buffer containing mappings for register set 0 | ||
| 2730 | ; SS:[EBP] -> regp stack frame | ||
| 2731 | ; DS = DGROUP | ||
| 2732 | ; | ||
| 2733 | ; EXIT: return code set on stack | ||
| 2734 | ; | ||
| 2735 | ; USED: EAX, EBX, ECX, EDX, ESI, EDI | ||
| 2736 | ; | ||
| 2737 | ; DESCRIPTION: This function sets the current register set number. | ||
| 2738 | ; If it is zero, it uses the save area specified in ES:DI. | ||
| 2739 | ; | ||
| 2740 | ;----------------------------------------------- | ||
| 2741 | Dword_Align _TEXT | ||
| 2742 | AMRS_set: | ||
| 2743 | cmp bl, FRS_COUNT ; Validate new Reg Set | ||
| 2744 | jae AMRS_inv_FRS | ||
| 2745 | movzx eax, bl | ||
| 2746 | imul eax, size FRS_struc | ||
| 2747 | xchg ax, bx | ||
| 2748 | lea bx, FRS_array[bx] ; Get pointer to the new Reg Set | ||
| 2749 | cmp [bx.FRS_alloc], 0 ; Make sure it is allocated | ||
| 2750 | xchg ax, bx | ||
| 2751 | je AMRS_undef_FRS ; unallocated, go complain | ||
| 2752 | |||
| 2753 | cmp bl, 0 ; New reg set 0? | ||
| 2754 | je short AMRS_set0 ; yes, always set context | ||
| 2755 | cmp bl, [CurRegSetn] ; Setting the same reg set? | ||
| 2756 | je AMRS_exit ; yes, just return | ||
| 2757 | AMRS_set0: ; Now set up new reg set | ||
| 2758 | mov word ptr [CurRegSet], ax ; Set Current reg. set Offset | ||
| 2759 | mov [CurRegSetn], bl | ||
| 2760 | |||
| 2761 | or bl, bl ; Real register set? | ||
| 2762 | jne _set_windows ; yes, go deal with it | ||
| 2763 | ; no, deal with reg set 0 | ||
| 2764 | mov ax, word ptr [bp.rES] ; Pick up user's pointer | ||
| 2765 | mov [EMM_savES], ax ; and save for AMRS_get | ||
| 2766 | mov dx, word ptr [bp.rDI] | ||
| 2767 | mov [EMM_savDI], dx ; AX:DX <-- regs cntxt restore area | ||
| 2768 | push ax | ||
| 2769 | or ax, dx | ||
| 2770 | pop ax | ||
| 2771 | jz _set_windows ; AX:DX == 0:0 implies no save area | ||
| 2772 | |||
| 2773 | ; construct GDT entry using EMM1_GSEL to access user's FRS buffer | ||
| 2774 | ; | ||
| 2775 | push es | ||
| 2776 | Set_EMM_GDT EMM1_GSEL | ||
| 2777 | pop es | ||
| 2778 | |||
| 2779 | mov fs, bx ; FS:SI <-- FRS buffer | ||
| 2780 | xor si, si | ||
| 2781 | lods word ptr fs:[si] ; get saved count | ||
| 2782 | movzx ecx, [_cntxt_pages] ; what it should be | ||
| 2783 | cmp ax, cx ; Sensible count? | ||
| 2784 | jne _set_windows ; no, restore last context | ||
| 2785 | Get_FRS_window DI | ||
| 2786 | shr ecx, 1 ; size in dwords | ||
| 2787 | push ds ; xchg ds,fs | ||
| 2788 | push fs | ||
| 2789 | pop ds | ||
| 2790 | pop fs ; use DS as default seg. reg. | ||
| 2791 | rep movsd | ||
| 2792 | push ds | ||
| 2793 | push fs | ||
| 2794 | pop ds | ||
| 2795 | pop fs | ||
| 2796 | jmp _set_windows ; set up mappings | ||
| 2797 | |||
| 2798 | page | ||
| 2799 | ;*********************************************** | ||
| 2800 | ; | ||
| 2801 | ; AMRS_size - get the size of the register set 0 save area | ||
| 2802 | ; | ||
| 2803 | ; ENTRY: | ||
| 2804 | ; SS:[EBP] -> regp stack frame | ||
| 2805 | ; DS = DGROUP | ||
| 2806 | ; | ||
| 2807 | ; EXIT: return code set on stack | ||
| 2808 | ; DX = size of the save area | ||
| 2809 | ; | ||
| 2810 | ; USED: none | ||
| 2811 | ; | ||
| 2812 | ; DESCRIPTION: This function returns the size of the save area used | ||
| 2813 | ; for register set 0. | ||
| 2814 | ; | ||
| 2815 | ;----------------------------------------------- | ||
| 2816 | AMRS_size: | ||
| 2817 | movzx eax, [_cntxt_bytes] ; Previously calculated value | ||
| 2818 | mov word ptr [bp.rDX], ax | ||
| 2819 | ret | ||
| 2820 | |||
| 2821 | page | ||
| 2822 | ;*********************************************** | ||
| 2823 | ; | ||
| 2824 | ; AMRS_allocate - allocate a fast register set | ||
| 2825 | ; | ||
| 2826 | ; ENTRY: | ||
| 2827 | ; SS:[EBP] -> regp stack frame | ||
| 2828 | ; DS = DGROUP | ||
| 2829 | ; | ||
| 2830 | ; EXIT: return code set on stack | ||
| 2831 | ; BL = register set number | ||
| 2832 | ; | ||
| 2833 | ; USED: EBX, ESI | ||
| 2834 | ; | ||
| 2835 | ; DESCRIPTION: This function allocates a free register set. | ||
| 2836 | ; | ||
| 2837 | ;----------------------------------------------- | ||
| 2838 | AMRS_allocate: | ||
| 2839 | cmp [FRS_free], 0 ; See if any are free | ||
| 2840 | je short AMRS_noRS ; no, none available | ||
| 2841 | ; Search for first free set | ||
| 2842 | dec [FRS_free] ; We are going to take one | ||
| 2843 | lea di, [FRS_array] ; Start of FRS structures | ||
| 2844 | xor bl, bl ; FRS number | ||
| 2845 | AMRS_search: | ||
| 2846 | cmp [di.FRS_alloc], 0 ; This one free? | ||
| 2847 | je short AMRS_foundRS ; yes, bl has the number | ||
| 2848 | add di, size FRS_struc ; on to the next one | ||
| 2849 | inc bl | ||
| 2850 | cmp bl, FRS_COUNT ; Safety... should never fail | ||
| 2851 | jb short AMRS_search | ||
| 2852 | |||
| 2853 | mov byte ptr [bp.rAX+1], EMM_SW_MALFUNCTION ; Honesty... | ||
| 2854 | ret | ||
| 2855 | |||
| 2856 | AMRS_foundRS: | ||
| 2857 | mov [di.FRS_alloc], 1 ; Allocate it | ||
| 2858 | Get_FRS_Window SI | ||
| 2859 | lea di, [di.FRS_Window] | ||
| 2860 | movzx ecx, [_cntxt_pages] | ||
| 2861 | shr ecx, 1 | ||
| 2862 | rep movsd ; Initialise to current mapping | ||
| 2863 | mov byte ptr [bp.rBX], bl ; Return the number | ||
| 2864 | ret | ||
| 2865 | |||
| 2866 | AMRS_noRS: ; None free; return error | ||
| 2867 | mov byte ptr [bp.rAX+1], NO_MORE_FRSETS | ||
| 2868 | ret | ||
| 2869 | |||
| 2870 | page | ||
| 2871 | ;*********************************************** | ||
| 2872 | ; | ||
| 2873 | ; AMRS_deallocate - deallocate a fast register set | ||
| 2874 | ; | ||
| 2875 | ; ENTRY: BL = register set to deallocate | ||
| 2876 | ; SS:[EBP] -> regp stack frame | ||
| 2877 | ; DS = DGROUP | ||
| 2878 | ; | ||
| 2879 | ; EXIT: return code set on stack | ||
| 2880 | ; | ||
| 2881 | ; USED: EAX | ||
| 2882 | ; | ||
| 2883 | ; DESCRIPTION: This function deallocates a register set. | ||
| 2884 | ; | ||
| 2885 | ;----------------------------------------------- | ||
| 2886 | AMRS_deallocate: | ||
| 2887 | or bl, bl | ||
| 2888 | jz AMRS_exit ; Deallocating 0 is ignored | ||
| 2889 | cmp bl, [CurRegSetn] ; Can't deallocate current set | ||
| 2890 | je short AMRS_undef_FRS | ||
| 2891 | cmp bl, FRS_COUNT | ||
| 2892 | jae short AMRS_undef_FRS ; Invalid Register set | ||
| 2893 | movzx eax, bl | ||
| 2894 | imul eax, size FRS_struc ; Offset into array | ||
| 2895 | xchg ax, bx | ||
| 2896 | cmp FRS_array[bx.FRS_alloc], 0 ; Paranoid... | ||
| 2897 | xchg ax, bx | ||
| 2898 | je short AMRS_undef_FRS ; Not allocated, complain | ||
| 2899 | xchg ax, bx | ||
| 2900 | mov FRS_array[bx.FRS_alloc], 0 ; Mark it free | ||
| 2901 | xchg ax, bx | ||
| 2902 | inc [FRS_free] ; one more set free | ||
| 2903 | ret | ||
| 2904 | |||
| 2905 | AMRS_Inv_FRS: | ||
| 2906 | AMRS_undef_FRS: | ||
| 2907 | mov byte ptr [bp.rAX+1], FRSET_UNDEFINED | ||
| 2908 | ret | ||
| 2909 | |||
| 2910 | _AlternateMapRegisterSet endp | ||
| 2911 | |||
| 2912 | |||
| 2913 | page | ||
| 2914 | ;****************************************************************************** | ||
| 2915 | ; _Get_Key_Val - use the timer to get a random number for OSDisable Key | ||
| 2916 | ; | ||
| 2917 | ; ENTRY DS, ES = DGROUP selectors | ||
| 2918 | ; | ||
| 2919 | ; STACK | ||
| 2920 | ; | ||
| 2921 | ; EXIT EAX has randomish number | ||
| 2922 | ; | ||
| 2923 | ; USES Flags, EAX, EDX | ||
| 2924 | ; | ||
| 2925 | ;------------------------------------------------------------------------------ | ||
| 2926 | _Get_Key_Val proc near | ||
| 2927 | call Get_Counter_Value ; (Who cares about the junk in | ||
| 2928 | mov dx, ax ; the high words...?) | ||
| 2929 | call Get_Counter_Value ; Likely to be very close | ||
| 2930 | mul edx ; Mess it all up! | ||
| 2931 | ret | ||
| 2932 | |||
| 2933 | _Get_Key_Val endp | ||
| 2934 | |||
| 2935 | ;****************************************************************************** | ||
| 2936 | ; | ||
| 2937 | ; NAME: | ||
| 2938 | ; Get_Counter_Value | ||
| 2939 | ; | ||
| 2940 | ; DESCRIPTION: | ||
| 2941 | ; Returns the current system timer counter value | ||
| 2942 | ; | ||
| 2943 | ; ENTRY: | ||
| 2944 | ; Assumes nothing | ||
| 2945 | ; | ||
| 2946 | ; EXIT: | ||
| 2947 | ; AX = Current counter value (High word of EAX NOT CHANGED) | ||
| 2948 | ; | ||
| 2949 | ; USES: | ||
| 2950 | ; Flags | ||
| 2951 | ; | ||
| 2952 | ;------------------------------------------------------------------------------ | ||
| 2953 | |||
| 2954 | Get_Counter_Value PROC NEAR | ||
| 2955 | |||
| 2956 | System_Clock_Port EQU 40h | ||
| 2957 | Sys_Clock_Ctrl_Port EQU 43h | ||
| 2958 | |||
| 2959 | Latch_Counter EQU 0 | ||
| 2960 | |||
| 2961 | mov al, Latch_Counter | ||
| 2962 | out Sys_Clock_Ctrl_Port, al ; Latch the timer counter | ||
| 2963 | jmp $+2 | ||
| 2964 | in al, System_Clock_Port ; Read the LSB | ||
| 2965 | mov ah, al | ||
| 2966 | jmp $+2 | ||
| 2967 | in al, System_Clock_Port ; Read the MSB | ||
| 2968 | xchg ah, al ; AX = Counter value | ||
| 2969 | ret | ||
| 2970 | |||
| 2971 | Get_Counter_Value ENDP | ||
| 2972 | |||
| 2973 | |||
| 2974 | _TEXT ENDS | ||
| 2975 | END | ||
| 2976 | |||
| 2977 | |||
| 2978 | \ No newline at end of file | ||