mkdep(1) seems to want the current directory on the include path,
[dragonfly.git] / sys / contrib / dev / acpica-unix-20031203 / common / a16utils.asm
1 NAME    BU_ASM
2 TITLE   BU_ASM.ASM -- ASM support for DOS BU_LIB
3
4 ;****************************************************************************
5 ;*      Copyright (C) Intel Corporation 1994-1999
6 ;*
7 ;*  All rights reserved.  No part of this program or publication
8 ;*  may be reproduced, transmitted, transcribed, stored in a
9 ;*  retrieval system, or translated into any language or computer
10 ;*  language, in any form or by any means, electronic, mechanical,
11 ;*  magnetic, optical, chemical, manual, or otherwise, without
12 ;*  the prior written permission of Intel Corporation.
13 ;****************************************************************************
14 ;
15 ;  To assemble with MASM61 -- ml /c a16utils.asm
16 ;
17 ;****************************************************************************
18
19 .286
20 .MODEL large, c
21
22 IFDEF MODEL_S
23 .MODEL small, c
24 ENDIF
25
26 IFDEF MODEL_M
27 .MODEL medium, c
28 ENDIF
29
30 IFDEF MODEL_L
31 .MODEL large, c
32 ENDIF
33
34 IFDEF MODEL_C
35 .MODEL compact, c
36 ENDIF
37
38 IFDEF MODEL_H
39 .MODEL huge, c
40 ENDIF
41
42 ;--------------------------------------------------------------------
43
44 GOREAL  MACRO
45     LOCAL   here
46
47     mov eax, cr0
48     and eax, 0fffffffeh
49     mov cr0, eax
50     jmp here
51 here:
52 ENDM
53
54 ;--------------------------------------------------------------------
55
56 GOPROT  MACRO
57     LOCAL here
58
59     xor eax, eax
60     xor edx, edx
61
62     mov ax, ds
63     shl eax, 4
64     lea edx, _gdt
65     add eax, edx
66
67     mov [_gdt_ptr+2], ax
68     shr eax, 16
69     mov [_gdt_ptr+4], ax
70
71     lgdt    FWORD PTR _gdt_ptr
72     mov eax, cr0
73     or  eax, 1
74     mov cr0, eax
75     jmp here
76 here:
77 ENDM
78 ;--------------------------------------------------------------------
79
80 .STACK
81 .DATA
82
83 PUBLIC  _dAPAwake, _dAPDone, _dAPFuncPtr, _wProcNumber, _bSPValid
84 PUBLIC  _wCSegDS, _wCSegES, _wCSegSS, _wCSegSP, _wASegDS, _wASegES
85 PUBLIC  _dAPHltJmp
86
87
88
89     emsfilename     DB      'EMMXXXX0',0
90
91     _dAPAwake   DD 0
92     _dAPDone    DD 0
93     _dAPFuncPtr DD 0
94     _wProcNumber    DW 0
95     _bSPValid   DB 0
96
97     _wASegDS    DW 0
98     _wASegES    DW 0
99     _wCSegDS    DW 0
100     _wCSegES    DW 0
101     _wCSegSS    DW 0
102     _wCSegSP    DW 0
103
104     _block      DW 0
105     _gdt_ptr    DW 23
106             DD 0
107     _gdt        DD 0        ; NULL descriptor
108             DD 0        ; NULL descriptor
109
110                     ; 64K real mode style data segment
111             DD 0ffffh   ; base 0, limit 0xffff
112             DD 00009200h    ; data, CPL=0, 16-bit, 1 byte granularity, r/w
113
114                     ; 4G flat data segment
115             DD 0ffffh   ; base 0, limit 0xfffff
116             DD 008f9200h    ; data, CPL=0, 16-bit, 4K granularity, r/w
117     _old_es     DW 0
118     _old_ds     DW 0
119     _old_fs     DW 0
120     _old_gs     DW 0
121     _dAPHltJmp  DD 0        ; jump to halt location
122
123 .CODE
124 EXTERNDEF pascal cprint:proc
125
126 PUBLIC  ems_present
127 ems_present PROC C
128     mov     ah,3dh                  ; open file
129     xor     al,al                   ; read only operation
130     mov     dx,offset emsfilename   ; look for EMMXXXX0
131     int     21h
132     jc      emserror1               ; if carry flag set, then no EMM driver
133
134     mov     di,ax                   ; save file handle
135     mov     bx,ax                   ; set up handle
136     mov     ax,4400h                ; get device (channel) info
137     int     21h
138
139     mov     ah,3eh                  ; close file
140     mov     bx,di                   ; close the file handle up
141     int     21h
142     jc      emserror1               ; if carry flag set, then no driver is present
143
144     test    dx,10000000b            ; if bit 7 not set, then the channel is a file
145     jz      emserror1               ; otherwise the channel is a device driver
146
147     mov     ax,1                    ; 1 = EMS present
148     ret
149
150 emserror1:
151     xor ax,ax           ; 0 = EMS not present
152     ret
153 ems_present ENDP
154
155 PUBLIC vm86
156 vm86        PROC C
157     smsw    ax
158     and ax, 1
159     ret
160 vm86    ENDP
161
162
163 PUBLIC _set_rows
164 _set_rows   PROC C rows:WORD
165     cmp rows, 25
166     je  set_25
167     cmp rows, 50
168     je  set_50
169     cmp rows, 132
170     je  set_132
171     jmp invalid_input
172 set_25:
173     mov ah, 00
174     mov al, 03
175     int 10h
176     mov ax, rows
177     jmp end_set_rows
178 set_50:
179     mov ah, 00
180     mov al, 03
181     int 10h
182     xor bx, bx
183     mov ah, 11h
184     mov al, 12h
185     int 10h
186     mov ax, rows
187     jmp end_set_rows
188 set_132:
189     mov ah, 00
190     mov al, 14h
191     int 10h
192     xor bx, bx
193     mov ah, 11h
194     mov al, 12h
195     int 10h
196     mov ax, rows
197     jmp end_set_rows
198 invalid_input:
199     xor ax, ax
200     jmp end_set_rows
201 end_set_rows:
202     ret
203 _set_rows   ENDP
204
205
206 PUBLIC  _cpuid_asm
207 _cpuid_asm  PROC C hv:DWORD, regs:PTR DWORD
208
209 check_8086:
210 .8086
211     pushf
212     pop ax
213     mov cx, ax
214     and ax, 0fffh
215     push    ax
216     popf
217     pushf
218     pop ax
219     and ax, 0f000h
220     cmp ax, 0f000h
221     mov ax, 10h
222     je  end_cpuid
223
224 check_80286:
225 .286
226     or  cx, 0f000h
227     push    cx
228     popf
229     pushf
230     pop ax
231     and ax, 0f000h
232     mov ax, 20h
233     jz  end_cpuid
234
235 check_80386:
236 .386
237     mov bx, sp
238     and sp, not 3
239     pushfd
240     pop eax
241     mov ecx, eax
242     xor eax, 40000h
243     push    eax
244     popfd
245     pushfd
246     pop eax
247     cmp ecx, eax
248     jne check_80486
249     mov ax, 30h
250     mov sp, bx
251     jmp end_cpuid
252
253 check_80486:
254 .486
255     pushfd
256     pop ecx
257     mov ecx, eax
258     xor eax, 200000h
259     push    eax
260     popfd
261     pushfd
262     pop eax
263     xor eax, ecx
264     mov ax, 40h
265     je  end_cpuid
266
267 check_cpuid:
268 .586
269     mov eax, hv
270     cpuid
271     push    ebx
272     IF  @DataSize       ; segment is far
273     les bx, regs
274     mov dword ptr es:[bx], eax
275     pop eax
276     mov dword ptr es:[bx + 4], eax
277     mov dword ptr es:[bx + 8], ecx
278     mov dword ptr es:[bx + 12], edx
279     ELSE                ; segment is near
280     mov bx, regs
281     mov dword ptr [bx], eax
282     pop eax
283     mov dword ptr [bx + 4], eax
284     mov dword ptr [bx + 8], ecx
285     mov dword ptr [bx + 12], edx
286     ENDIF
287     mov ax, 5
288 end_cpuid:
289     ret
290 _cpuid_asm  ENDP
291
292 .386p
293 ;--------------------------------------------------------------------
294 ; Pentium Pro MSRs - from Pentium Pro Developer's Manual
295 ;   January 1996 - Appendix C
296 ;
297 ; MTRRs: 200h - 20Fh, 250h, 258h - 259h, 268h - 26Fh, 2FFh
298 ;--------------------------------------------------------------------
299 PUBLIC  _read_msr
300 _read_msr   PROC    C dmsr:DWORD, pqmsr:PTR DWORD
301     pushad
302     mov ecx, dmsr
303     dw  320fh           ; RDMSR
304     les bx, pqmsr
305     mov DWORD ptr es:[bx], eax
306     mov DWORD ptr es:[bx + 4], edx
307     popad
308     ret
309 _read_msr   ENDP
310
311 ;--------------------------------------------------------------------
312
313 PUBLIC  _write_msr
314 _write_msr  PROC    C dmsr:DWORD, pqmsr:PTR DWORD
315     pushad
316     les bx, pqmsr
317     mov eax, DWORD ptr es:[bx]
318     mov edx, DWORD ptr es:[bx + 4]
319     mov ecx, dmsr
320     dw  300fh           ; WRMSR
321     popad
322     ret
323 _write_msr  ENDP
324
325 ;----------------------------------------------------------------------------
326 ; Procedure:    dReadCR0 - Reads CR0 CPU Register
327 ;
328 ; Output:   dx:ax and eax - Contents of CR0
329 ;
330 ; Registers:    All registers preserved except EAX and EDX
331 ;----------------------------------------------------------------------------
332 PUBLIC  dReadCR0
333 dReadCR0    PROC C
334     mov eax, cr0
335     mov edx, eax
336     shr edx, 16     ; upper 16 bits in dx
337     ret
338 dReadCR0    ENDP
339
340 ;----------------------------------------------------------------------------
341 ; Procedure:    dReadCR2 - Reads CR2 CPU Register
342 ;
343 ; Output:   dx:ax and eax - Contents of CR2
344 ;
345 ; Registers:    All registers preserved except EAX and EDX
346 ;----------------------------------------------------------------------------
347 PUBLIC  dReadCR2
348 dReadCR2    PROC C
349     mov eax, cr2
350     mov edx, eax
351     shr edx, 16     ; upper 16 bits in dx
352     ret
353 dReadCR2    ENDP
354
355 ;----------------------------------------------------------------------------
356 ; Procedure:    dReadCR3 - Reads CR3 CPU Register
357 ;
358 ; Output:   dx:ax and eax - Contents of CR3
359 ;
360 ; Registers:    All registers preserved except EAX and EDX
361 ;----------------------------------------------------------------------------
362 PUBLIC  dReadCR3
363 dReadCR3    PROC C
364     mov eax, cr3
365     mov edx, eax
366     shr edx, 16     ; upper 16 bits in dx
367     ret
368 dReadCR3    ENDP
369
370
371 .586
372 ;----------------------------------------------------------------------------
373 ; Procedure:    dGetProcUpdateRev_asm - Reads PPP Update Revision via an MSR
374 ;
375 ; Output:   dx:ax and eax - PPP Update Revision
376 ;
377 ; Registers:    All registers preserved except EAX, ECX, and EDX
378 ;----------------------------------------------------------------------------
379 PUBLIC _dGetProcUpdateRev_asm
380 _dGetProcUpdateRev_asm  PROC    C
381     mov ecx, 08Bh   ; model specific register to write
382     xor eax, eax
383     xor edx, edx
384     dw  300Fh       ; WRMSR ==> load 0 to MSR at 8Bh
385     mov eax, 1
386     cpuid
387     mov ecx, 08Bh   ; model specific register to read
388     dw  320Fh       ; RDMSR ==> EDX = (read) MSR 8Bh
389     mov eax, edx    ; return EAX
390     shr edx, 16 ; return DX:AX
391     ret
392 _dGetProcUpdateRev_asm  ENDP
393
394 ;--------------------------------------------------------------------
395
396 PUBLIC  iInterruptFlagState
397 iInterruptFlagState PROC
398     pushf
399     pop ax
400     and ax, 200h
401     shr ax, 9
402     ret
403 iInterruptFlagState ENDP
404
405 ;--------------------------------------------------------------------
406
407 .586P
408 PUBLIC  vRealFsGs
409 vRealFsGs       PROC C
410
411     ; TBD:  verify this on an AMD K6-2 266 MHz
412     ; Assert A20M# via system control port A (This is a
413     ; system dependent feature).
414     in  al, 92h
415     and al, 0fdh
416     out 92h, al     ; re-assert A20M#
417
418     GOPROT
419
420     mov ax, 8
421     mov gs, ax
422
423     GOREAL
424
425     mov ax, [_old_fs]   ; restore original
426     mov fs, ax
427     mov ax, [_old_gs]   ; restore original
428     mov gs, ax
429     sti
430     ret
431 vRealFsGs       ENDP
432
433 ;--------------------------------------------------------------------
434 PUBLIC  vFlatFsGs
435 vFlatFsGs       PROC C
436     cli
437     mov ax, fs
438     mov [_old_fs], ax   ; save  original fs
439     mov ax, gs
440     mov [_old_gs], ax   ; save  original gs
441
442     ; Deassert A20M# via system control port A (This is a
443     ; system dependent feature)
444     in  al, 92h
445     or  al, 2
446     out 92h, al     ; de-assert A20M#
447
448     GOPROT
449
450     mov ax, 10h
451     mov fs, ax
452     mov gs, ax
453
454     GOREAL
455
456     ret
457 vFlatFsGs       ENDP
458
459
460 PUBLIC  vRealEsDs
461 vRealEsDs       PROC C
462
463     ; TBD:  verify this on an AMD K6-2 266 MHz
464     ; Assert A20M# via system control port A (This is a
465     ; system dependent feature).
466     in  al, 92h
467     and al, 0fdh
468     out 92h, al     ; re-assert A20M#
469
470     GOPROT
471
472     mov ax, 8
473     mov gs, ax
474
475     GOREAL
476
477     mov ax, [_old_es]   ; restore original
478     mov es, ax
479     mov ax, [_old_gs]   ; restore original
480     mov gs, ax
481     sti
482     ret
483 vRealEsDs       ENDP
484
485 ;--------------------------------------------------------------------
486 PUBLIC  vFlatEsDs
487 vFlatEsDs       PROC C
488     cli
489     mov ax, es
490     mov [_old_es], ax   ; save  original
491     mov ax, gs
492     mov [_old_gs], ax   ; save  original
493
494     ; Deassert A20M# via system control port A (This is a
495     ; system dependent feature)
496     in  al, 92h
497     or  al, 2
498     out 92h, al     ; de-assert A20M#
499
500     GOPROT
501
502     mov ax, 10h
503     mov es, ax
504     mov gs, ax
505
506     GOREAL
507
508     ret
509 vFlatEsDs       ENDP
510
511 PUBLIC print
512 print PROC PASCAL Seq:DWORD
513
514
515     pushad
516     mov     eax, Seq
517     push    eax
518     call    cprint
519     popad
520
521     ret
522 print ENDP
523
524 PUBLIC  DoMove
525 DoMove       PROC    
526
527     push    edx
528 ;    GOPROT
529     pop     edx
530
531     mov     ecx, edx
532     shr     ecx, 2          ; byte count / 4 = dword count
533     cmp     ecx, 0
534     je      DoBytes 
535
536 NextDword:
537     xor     eax, eax
538     lock or eax, gs:[esi]
539 ;    mov     eax, gs:[esi]
540
541     mov     gs:[edi], eax
542
543     add     esi, 4
544     add     edi, 4
545     loop    NextDword
546
547 DoBytes:
548     mov     ecx, edx
549     and     ecx, 3
550     cmp     ecx, 0
551     je      Exit            ; no extra bytes to move
552
553 NextByte:
554     mov     al, byte ptr gs:[esi]
555     mov     byte ptr gs:[edi], al
556     inc     esi
557     inc     edi
558     loop    NextByte
559
560 Exit:
561 ;    GOREAL
562     ret       
563     
564 DoMove       ENDP
565     .586
566
567  
568 ;--------------------------------------------------------------------
569
570 PUBLIC  _WriteApic
571 _WriteApic  PROC C
572     call    vFlatFsGs
573     xor ecx, ecx
574     xor edx, edx
575
576     mov cx, [esp+6] ; high  word of apic address
577     shl ecx, 16
578     mov cx, [esp+4] ; low word of apic address
579
580     mov dx, [esp+10]    ; high  word of apic command
581     shl edx, 16
582     mov dx, [esp+8] ; low word of apic command
583
584     mov gs:[ecx], edx
585
586     call    vRealFsGs
587     ret
588 _WriteApic  ENDP
589
590 ;--------------------------------------------------------------------
591
592 PUBLIC  _ReadApic
593 _ReadApic   PROC C
594     call    vFlatFsGs
595     xor ecx, ecx
596
597     mov cx, [esp+6] ; low word of apic address
598     shl ecx, 16
599     mov cx, [esp+4] ; high  word of apic address
600
601     mov eax, gs:[ecx]
602
603     push    eax     ; save  eax
604     call    vRealFsGs
605     pop eax     ; restore eax
606
607     mov edx, eax
608     shr edx, 16
609     ret
610 _ReadApic   ENDP
611
612 ;--------------------------------------------------------------------
613 ; Since the AP shares the BSP's stack, coordination is needed to avoid
614 ; simultaneous usage by both processors, which would cause corruption.
615 ;
616 ; While the AP is executing here, the BSP is executing the code
617 ; which follows the call to vAPStartupAll() or vAPStartupOne()
618 ; in bu_apic.c:vExecuteOnAPs(). After disabling interrupts,
619 ; the BSP stores the sp value in _wCSegSP, sets _bSPValid to 1,
620 ; and spins while _dAPDone != _dAPAwake. (Both are initially zero;
621 ; the code below increments _dAPAwake before spinning on _bSPValid.)
622 ;
623 ; XXX - There is a race condition here:  if the BSP makes it all
624 ; XXX - the way to its spin loop on _dAPDone != _dAPAwake before
625 ; XXX - the AP increments _dAPAwake, the BSP will exit the spin
626 ; XXX - loop without actually having waited for the AP to finish.
627
628 PUBLIC  _vSetupAP
629 _vSetupAP   PROC C
630     cli
631     mov ax, @data
632     mov ds, ax
633     mov esp, 0
634     lock    inc dword ptr [_dAPAwake]
635 spin1:
636     mov al, [_bSPValid]
637     cmp al, 1
638     jne spin1
639 ; XXX - The following line is supposed to provide some validity checking,
640 ; XXX - but it does not entirely succeed. It is possible for > 1 AP to
641 ; XXX - see _bSPValid == 1, and exit the spin1 loop just above, before
642 ; XXX - the first one out has had time to decrement _bSPValid; this race
643 ; XXX - defeats the purpose of decrementing it. The decrement is likely
644 ; XXX - not needed anyway due to the exclusion provided by the spin2 loop
645 ; XXX - below.
646     lock dec byte ptr[_bSPValid]
647
648     mov ax, [_wCSegSS]
649     mov ss, ax
650     mov sp, [_wCSegSP]
651
652 ; critical section - determining unique cpu signatures
653
654 spin2:
655     mov eax, 1
656 ; XXX - Should the following line have a 'lock' prefix?
657     xchg    word ptr [_block], ax
658     test    ax, ax
659     jne spin2
660
661     mov ax, ds          ; Save ASM DS and ES in global vars
662     mov [_wASegDS], ax
663     mov ax, es
664     mov [_wASegES], ax
665
666     mov ax, [_wCSegES]
667     mov es, ax
668     mov ax, [_wCSegDS]      ; Restore C DS and ES from global vars
669     mov ds, ax
670
671 ; Update Current Processor Number. Mutual exclusion from other AP's is
672 ; guaranteed by the spin2 loop above.
673 ; Note that the "processor number" determined here represents the order
674 ; in which the processors happened to get through the spin2 lock, and
675 ; has nothing to do with APIC numbers. A system having > 1 AP will not
676 ; necessarily number the AP's consistently from one run to the next.
677     mov eax, [_dAPDone]
678     inc eax
679     mov [_wProcNumber], ax
680
681     call    [_dAPFuncPtr]       ; _dAPFuncPtr needs to point to a void function
682
683     mov ax, [_wASegDS]      ; Restore ASM DS and ES from global vars
684     mov ds, ax
685     mov ax, [_wASegES]
686     mov es, ax
687
688     lock    inc dword ptr [_dAPDone]
689     lock    inc byte ptr [_bSPValid]
690
691     xor eax, eax
692 ; A simple 'mov' would serve as well as the following 'xchg'.
693     xchg    word ptr [_block], ax
694     wbinvd
695     mov si, offset _dAPHltJmp
696     jmp dword ptr [si]      ; Jump to HLT, JMP $-1 in F000 segment
697     hlt             ; Should never get here
698 _vSetupAP   ENDP
699
700 ;--------------------------------------------------------------------
701
702 PUBLIC  bIn8
703 bIn8    PROC    C wPort:WORD
704     xor ax, ax
705     mov dx, wPort
706     in  al, dx
707     ret
708 bIn8    ENDP
709
710 ;--------------------------------------------------------------------
711
712 PUBLIC  wIn16
713 wIn16   PROC    C wPort:WORD
714     mov dx, wPort
715     in  ax, dx
716     ret
717 wIn16   ENDP
718
719 ;--------------------------------------------------------------------
720
721 PUBLIC  dIn32
722 dIn32   PROC    C wPort:WORD
723     mov dx, wPort
724     in  eax, dx
725     mov edx, eax
726     shr edx, 16
727     ret
728 dIn32   ENDP
729
730 ;--------------------------------------------------------------------
731
732 PUBLIC  vOut8
733 vOut8   PROC    C wPort:WORD, bValue:BYTE
734     mov dx, wPort
735     mov al, bValue
736     out dx, al
737     ret
738 vOut8   ENDP
739
740 ;--------------------------------------------------------------------
741
742 PUBLIC  vOut16
743 vOut16  PROC    C wPort:WORD, wValue:WORD
744     mov dx, wPort
745     mov ax, wValue
746     out dx, ax
747     ret
748 vOut16  ENDP
749
750 ;--------------------------------------------------------------------
751
752 PUBLIC  vOut32
753 vOut32  PROC    C wPort:WORD, dValue:DWORD
754     mov dx, wPort
755     mov eax, dValue
756     out dx, eax
757     ret
758 vOut32  ENDP
759
760 ;--------------------------------------------------------------------
761
762 ;   int FlatMove (DWORD dPhysicalDestination, DWORD dPhysicalSource, size_t sSize)
763 PUBLIC  FlatMoveX
764 FlatMoveX   PROC    C dDest:DWORD, dSrc:DWORD, sSize:WORD
765     call    vm86            ; check if VM86 mode
766     cmp     ax, 0
767     jne     NotRealMode     ; skip memory move if not in real mode
768
769     call    vFlatFsGs       ; set up FS and GS as 4GB limit selectors with
770                             ; base 0:0 and de-assert A20M#
771     
772     movzx   ecx, sSize
773     cmp     ecx, 0
774     je      SKipMemoryMove  ; skip memory move if 0==sSize
775
776     mov     eax, dDest
777     cmp     eax, 400h
778     jbe     SkipMemoryMove  ; skip memory move if destination is 40:0
779                             ; BIOS Data Area or less (IVT)
780
781     mov     ebx, dSrc
782 NextByte:
783     mov     dl, gs:[ebx][ecx - 1]
784     mov     gs:[eax][ecx - 1], dl
785     loop    NextByte
786
787     call    vRealFsGs
788     xor     ax, ax
789 NotRealMode:
790     ret
791
792 SkipMemoryMove:
793     mov ax, 1               ; return error code
794     ret
795 FlatMoveX   ENDP
796
797
798 ;   int FlatMove32 (DWORD dPhysicalDestination, DWORD dPhysicalSource, size_t sSize)
799 PUBLIC  FlatMove32
800 FlatMove32   PROC    C      dDest:DWORD, dSrc:DWORD, sSize:WORD  
801
802     call    vm86            ; check if VM86 mode
803     cmp     ax, 0
804     jne     NotRealMode     ; skip memory move if not in real mode
805      
806     call    vFlatFsGs       ; set up FS and GS as 4GB limit selectors with
807                             ; base 0:0 and de-assert A20M#
808     movzx   edx, sSize 
809     mov     esi, dSrc
810     mov     edi, dDest
811
812     push    edx
813     call    print
814     push    esi
815     call    print
816     push    edi
817     call    print
818     
819     cmp     edx, 0
820     je      SkipMemoryMove  ; skip memory move if 0==sSize
821
822     cmp     edi, 400h
823     jbe     SkipMemoryMove  ; skip memory move if destination is 40:0
824                             ; BIOS Data Area or less (IVT)
825     call    DoMove          ; edx=Count, esi=src, edi=dst
826
827     movzx   ecx, sSize
828     shr     ecx, 2
829     mov     edi, dDest
830 PrintLoop:
831     mov     eax, gs:[edi]
832     push    eax
833     call    print
834     add     edi, 4
835     loop    PrintLoop
836
837     call    vRealFsGs
838     xor     ax, ax
839
840 NotRealMode:
841     ret
842
843 SkipMemoryMove:
844     call    print
845     call    vRealEsDs
846     mov     ax, 1           ; return error code
847     ret         
848     
849 FlatMove32  ENDP
850
851
852 ;   int FlatMove32 (DWORD dPhysicalDestination, DWORD dPhysicalSource, size_t sSize)
853 PUBLIC  FlatMove32x
854 FlatMove32x   PROC    C dDest:DWORD, dSrc:DWORD, sSize:WORD
855     call    vm86            ; check if VM86 mode
856     cmp     ax, 0
857     jne     NotRealMode     ; skip memory move if not in real mode
858
859     call    vFlatFsGs       ; set up FS and GS as 4GB limit selectors with
860                             ; base 0:0 and de-assert A20M#
861     movzx   ecx, sSize
862     cmp     ecx, 0
863     je      SKipMemoryMove  ; skip memory move if 0==sSize
864
865     mov     eax, dDest
866     cmp     eax, 400h
867     jbe     SkipMemoryMove  ; skip memory move if destination is 40:0
868                             ; BIOS Data Area or less (IVT) 
869                             
870     mov     ebx, dSrc
871     mov     esi, 0
872
873     push    ecx
874     call    print
875     push    ebx
876     call    print
877     push    eax
878     call    print
879
880     shr     ecx, 2          ; byte count / 4 = dword count
881     cmp     ecx, 0
882     je      DoBytes
883
884 NextDword:
885     mov     edx, dword ptr gs:[ebx][esi]
886     mov     dword ptr gs:[eax][esi], edx
887     push    edx
888     call    print
889     add     esi, 4
890     loop    NextDword
891
892 DoBytes:
893     movzx   ecx, sSize
894     and     ecx, 3
895     cmp     ecx, 0
896     je      Exit            ; no extra bytes to move
897
898 NextByte:
899     mov     dl, gs:[ebx][esi]
900     mov     gs:[eax][esi], dl
901     inc     esi
902     loop    NextByte
903
904 Exit:
905     call    vRealFsGs
906     xor     ax, ax
907
908 NotRealMode:
909     ret
910
911 SkipMemoryMove:
912     mov ax, 1               ; return error code
913     ret
914 FlatMove32x   ENDP
915 END