Copy an Option ROM to a file

.James Zou.

10/24/2010 

Many years ago, I designed a remote server management PCI card. On this card, I was using the ATI Rage XL VGA controller. I asked ATI guys to design a special Video Option ROM for me. The problem is when the system boot up into Windows system, we  saw double screens. On ATI standard VGA card, we did not see this problem. My idea is to download the video option ROM from their standard VGA card, burn it into my remote server management PCI card and see if the problem exists. I wrote  an  assembly language program to download the Video Option ROM.

The Key point is to switch the real mode to protect mode. If you understand this program well, you must be an expert of x86 architecture (no kidding).

(1) Create a file called vga_main.asm
Extrn _go_to_flat_mode:near

cgroup  group   cseg
cseg    segment word public ‘CODE’
 assume  cs:cgroup, ds:cgroup, es:nothing, ss:nothing
start: 
.386
  push cs
  pop  ds
  call _go_to_flat_mode
  mov  esi,0feac0000h  
  mov  cx,8000h
  push 5000h
  pop  es
  xor  edi,edi
next_byte:  
  mov  al,[esi]
  mov  es:[edi],al
  inc  esi
  inc  edi
  loop next_byte
  

  mov  ah,4ch
  int  21h

cseg  ends
 end  start

 (2) Create a file called go_to_flat_mode.asm

;*****************************************************************;
;
;*****************************************************************;
;—————————————;

;—————————————;
;       EXTERNAL DEFINITIONS            ;
;—————————————;
;; extrn   file_handle: word
;; extrn   rom_filename:byte
;; Vitaliy
;; extrn old_gdtr_value:fword
;; extrn   old_cr0_value:dword
;; extrn pmode_status:byte

;—————————————;
;       PUBLIC DEFINITIONS              ;
;—————————————;
 public  _go_to_flat_mode
 public  _go_to_real_mode

;—————————————;
; CODE SEGMENT   ;
;—————————————;
cgroup  group   cseg
cseg    segment word public ‘CODE’
 assume  cs:cgroup, ds:cgroup, es:nothing, ss:nothing
.586p
old_gdtr_value df ?
old_cr0_value dd ?
pmode_status db ?

;—————————————;
;       go_to_FLAT_MODE                 ;
;  This routine puts the processor in   ;
;  the flat mode.                       ;
;—————————————;
_go_to_flat_mode        proc    near
 push    ax
 push    dx
 mov cs:pmode_status,0  ; assume we are not in pmode
 smsw  ax                      ; put machine staus word in ax
        test  al,01h                  ; are we in protected mode ?
        jz  not_in_protected_mode   ; if no, dont save gdtr and cr0
 mov cs:pmode_status,1          ; remember we were in pmode
not_in_protected_mode:
 call    enable_8042_bit_20
 mov     dl,1                    ; 4GB limit
 call    SetLimitToDS            ; Set segment limit as 4GB
 xor     ax, ax
 mov     ds, ax
 mov     es, ax
 pop     dx
 pop     ax
 ret
_go_to_flat_mode        endp

;—————————————;
;       go_to_real_MODE                 ;
;  This routine takes the processor     ;
;  out of flat mode.                    ;
;—————————————;
_go_to_real_mode        proc    near
 push    dx
 mov     dl,0                            ; 64KB limit
 call    SetLimitToDS                    ; Set segment limit as 64KB
;        call    disable_8042_bit_20             ; Disable GateA20 line
 pop     dx
 ret
_go_to_real_mode        endp

;*****************************************************************************;

;—————————————————————————–;
;                               SET LIMIT TO DS                               ;
;—————————————————————————–;
;       Sets the segment limit to DS (and ES) register                        ;
;       Input   : DL =  0: 64KB limit                                         ;
;                       1: 4GB limit                                          ;
;       Output  : none                                                        ;
;       Reg use : does not destroy any register                               ;
;—————————————————————————–;

SetLimitToDS:
 pushf
 push    eax
 push    ebx
 cli                                     ; Disable interrupt
 mov     al,8dh
 out     70h,al                          ; Disable NMI

 xor     eax,eax
 xor     ebx,ebx
 mov     ax,cs
 shl     eax,4
 mov     bx,offset FlatGDT
 add     eax,ebx                         ; EAX = 32 bit linear address

 mov     bx,offset GDTDesc
 mov     cs:[bx].PSEUDODESCSTRUC.dGDTaddr,eax
 call    enable_8042_bit_20              ; Enable GateA20 line
 sgdt cs:fword ptr [old_gdtr_value]  ; Save old GDTR value
 mov  eax,cr0           ; Save old CR0 value
 mov cs:old_cr0_value,eax
 lgdt    cs:fword ptr GDTDesc  ; Load GDTR
 mov     eax,cr0
 or      al,01                           ; Enable protected mode
 mov     cr0,eax                         ; Write to control reg0
 jmp     pm_flush_queue
pm_flush_queue:
 mov     ax,(offset DataDesc4GB – offset FlatGDT)
 or      dl,dl                           ; 4GB limit ?
 jnz     ok_limit                        ; Yes..
 mov     ax,(offset DataDesc64KB – offset FlatGDT)
ok_limit:
 mov     ds,ax                           ; DS = data desc, 4GB limit
 cmp cs:pmode_status,1
 jz restore_gdtr_and_cr0
 mov     eax,cr0
 and     al,0feh                         ; Disable protected mode
 mov     cr0,eax                         ; Write to CR0
 jmp     rm_flush_queue
restore_gdtr_and_cr0:
 lgdt cs:fword ptr [old_gdtr_value]  ; Restore old GDTR value
 mov  eax,cs:old_cr0_value         ; Restore old CR0 value
 mov     cr0,eax                         ; Write to CR0

rm_flush_queue:
 pop     ebx
 pop     eax
 popf
 ret

;—————————————;
;       Definition of Descriptors       ;
;—————————————;

DESCSTRUC               STRUCT

 wLimit0_15      word    ?               ; Segment limit (A0 – A15)
 wBase0_15       word    ?               ; Base address (A0 – A15)
 bBase16_23      byte    ?               ; Base address (A16 – A23)
 bAtribute       byte    ?               ; Defines attribute of the seg
 bLimit16_19     byte    ?               ; Granularity/seg limit 16-19
 bBase24_31      byte    ?               ; Base address (A24 – A31)

DESCSTRUC               ENDS

PSEUDODESCSTRUC         STRUCT

 wGDTLimit       word    ?               ; Current GDT limit
 dGDTaddr        dword   ?               ; GDT 32-bit address

PSEUDODESCSTRUC         ENDS

;—————————————;
;       Descriptor Flag EQUATES         ;
;—————————————;

 Accessed        EQU     00000001b       ; Segment is accessed
 Writable        EQU     00000010b       ; Segment is writable (data)
 Readable        EQU     00000010b       ; Segment is readable (code)
 ExpandDown      EQU     00000100b       ; Segment is expand-down mode
 DPL0            EQU     00000000b       ; Descriptor Previlage level-0
 DPL1            EQU     00100000b       ; Descriptor Previlage level-1
 DPL2            EQU     01000000b       ; Descriptor Previlage level-2
 DPL3            EQU     01100000b       ; Descriptor Previlage level-3
 Available       EQU     00010000b       ; Segment available for system
 Big             EQU     01000000b       ; Big mode (32bit operand) on
 Granularity4K   EQU     10000000b       ; Segment limit = 4GB

;—————————————;
;       GLOBAL DESCRIPTOR TABLE         ;
;—————————————;
; Format of this table :                ;
; ——————–                  ;
;                                       ;
;    1st entry : Null descriptor        ;
;    2nd entry : GDT descriptor         ;
;    3rd entry : Code seg descriptor    ;
;    4th entry : Data seg descriptor    ;
;    5th entry : Stack seg descriptor   ;
;—————————————;

  even
FlatGDT:

 NullDesc        DESCSTRUC       {0,0,0,0,0,0}

 DataDesc4GB     DESCSTRUC       {\
       0ffffh,
       0000h,
       00h,
       (90h or DPL0 or Writable),
       (0fh or Granularity4K),
       00h\
     }

 DataDesc64KB    DESCSTRUC       {\
       0ffffh,
       0000h,
       00h,
       (90h or DPL0 or Writable),
       00h,
       00h\
     }
FlatGDTEnd:

;—————————————————————————–;

GDTDesc         PSEUDODESCSTRUC {\
      (offset FlatGDTEnd – offset FlatGDT),
      00000000h\
    }

enable_addr_bit_20:
enable_8042_bit_20:
 mov     ah,0dfh
 jmp     short ed_1
disable_addr_bit_20:
disable_8042_bit_20:
 mov     ah,0ddh
ed_1:
 mov     al,0d1h
 out     64h,al
ed_3:
 jcxz    $+2
 in      al,64h
 test    al,2
 jnz     ed_3
 mov     al,ah
 out     60h,al
ib_free:
 in      al,64h                  ; wait till i/p empty
 test    al,00000010b            ; i/p buffer full bit
 jnz     ib_free                 ; buffer empty or time out
;;10/20/98
 mov al,0ffh
 out 64h,al
ed_5:
 in al,64h
 test al,00000010b
 jnz ed_5
 ret

;—————————————;
;—————————————;
cseg    ends
 end

Advertisements

About superjameszou

Hardware Design Engineer
This entry was posted in Assembly Language. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s