home *** CD-ROM | disk | FTP | other *** search
- PAGE ,132
- TITLE Method 1
- .286C ; Tell MASM 2.0 about 286 instructions
- ;--------------------------------------------------------------:
- ; Sample Program 1 :
- ; :
- ; This program switches into Protected Virtual Mode, changes :
- ; the display attribute to reverse video, and returns to Real :
- ; Mode to exit to DOS :
- ; :
- ; Once entered into a file, do the following: :
- ; MASM SAMPLE1; :
- ; LINK SAMPLE1; :
- ; EXE2BIN SAMPLE1 SAMPLE1.COM :
- ; DEL SAMPLE1.EXE :
- ; :
- ; WARNING: This program will "kill" a PC. I should only :
- ; be run on an AT. :
- ;--------------------------------------------------------------:
-
- bios_data_seg SEGMENT at 0040h
- ORG 0067h
- io_rom_init dw ? ; dword variable in BIOS data segment
- - More (Y/N/NS)? ns
- io_rom_seg dw ? ; used to store a dword address
- bios_data_seg ENDS
-
- descriptor STRUC
- seg_limit dw 0 ; segment limit (1-65536 bytes)
- base_lo_word dw 0 ; 24 bit physical address
- base_hi_byte db 0 ; (0 - (16M-1))
- access_rights db 0 ; access rights byte
- dw 0 ; reserved_386
- descriptor ENDS
-
- cmos_port equ 070h
- code_seg_access equ 10011011b ;access rights byte for code seg
- data_seg_access equ 10010011b ;access rights byte for data seg
- disable_bit20 equ 11011101b ;8042 function code to de-gate A20
- enable_bit20 equ 11011111b ;8042 function code to gate A20
- inta01 equ 021h ;8259 Int Controller #1
- intb01 equ 0A1h ;8259 Int Controller #2
- port_a equ 060h ;8042 port A
- shut_cmd equ 0FEh ;cmd to 8042: shut down AT
- shut_down equ 00Fh ;CMOS shut down byte index
- status_port equ 064h ;8042 status port
- virtual_enable equ 0001h ;LSB=1: Protected Virtual Mode
-
- SUBTTL Macro Definitions
- PAGE
- ;--------------------------------------------------------------:
- ; These mnemonics are not supported in MASM 2.0 therefore :
- ; they are supplied here as MACROS. :
- ;--------------------------------------------------------------:
- lgdt MACRO lgdt1 ;; Load Global Descriptor Table
- LOCAL lgdt2,lgdt3
- db 00Fh
- lgdt2 label byte
- mov dx,word ptr lgdt1
- lgdt3 label byte
- org offset lgdt2
- db 001h
- org offset lgdt3
- ENDM
-
- lmsw MACRO lmsw1 ;; Load Machine Status Word
- LOCAL lmsw2,lmsw3
- db 00Fh
- lmsw2 label byte
- mov si,ax
- lmsw3 label byte
- org offset lmsw2
- db 001h
- org offset lmsw3
- ENDM
-
- ;; This is a "hard coded" far jump
- jumpfar MACRO jumpfar1,jumpfar2
- db 0EAh
- dw (offset jumpfar1)
- dw jumpfar2
- ENDM
-
- SUBTTL Program entry point and data area
- PAGE
- cseg SEGMENT para public 'code'
- ASSUME cs:cseg
-
- ORG 100h
- start: jmp short main
-
- EVEN
- gdt LABEL word
-
- gdt_desc EQU (($-gdt)/8)*8 + 0000000000000000b
- gdt1 descriptor <gdt_leng,,,data_seg_access,>
- cs_code EQU (($-gdt)/8)*8 + 0000000000000000b
- gdt2 descriptor <cseg_leng,,,code_seg_access,>
- cs_data EQU (($-gdt)/8)*8 + 0000000000000000b
- gdt3 descriptor <cseg_leng,,,data_seg_access,>
- ss_desc EQU (($-gdt)/8)*8 + 0000000000000000b
- gdt4 descriptor <0FFFFh,,,data_seg_access,>
- ds_desc equ (($-gdt)/8)*8 + 0000000000000000b
- gdt5 descriptor <0FFFFh,,,data_seg_access,>
- es_desc equ (($-gdt)/8)*8 + 0000000000000000b
- gdt6 descriptor <0FFFFh,,,data_seg_access,>
- gdt_leng EQU $-gdt
- PAGE
- ;--------------------------------------------------------------:
- ; Format of the Segment Selector Component: :
- ; :
- ; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ :
- ; | INDEX +TI+ RPL + :
- ; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ :
- ; :
- ; TI = Table Indicator (0=GDT, 1=LDT) :
- ; RPL = Requested Privelege Level (00 = highest; 11 = Lowest) :
- ;--------------------------------------------------------------:
- ; Format of the Global Descriptor Table :
- ; .-----------+ +---> TI :
- ; V | |++-> RPL :
- ; GDT ==> +---------------+ | ||| :
- ; | GDT_DESC | --+ 0000000000000000b :
- ; +---------------+ :
- ; | CS_CODE | 0000000000001000b :
- ; +---------------+ :
- ; | CS_DATA | 0000000000010000b :
- ; +---------------+ :
- ; | SS_DESC | 0000000000011000b :
- ; +---------------+ :
- ; | DS_DESC | 0000000000100000b :
- ; +---------------+ :
- ; | ES_DESC | 0000000000101000b :
- ; +---------------+ :
- ;--------------------------------------------------------------:
-
- i8259_1 db ? ; store for status of 8259 #1
- i8259_2 db ? ; store for status of 8259 #2
-
- SUBTTL Program Main
- PAGE
- ;--------------------------------------------------------------:
- ; MAIN :
- ;--------------------------------------------------------------:
- ASSUME ds:cseg
- main PROC ;ES=DS=CS
- cld ;forward
-
- mov dx,cs ;form 24bit address out of
- mov cx,offset gdt ; CS:GDT
- call form_24bit_address
- mov gdt1.base_lo_word,dx ;DESC now points to gdt
- mov gdt1.base_hi_byte,cl
-
- mov dx,cs ;form 24bit address out of
- xor cx,cx ; CS:0000
- call form_24bit_address
- mov gdt2.base_lo_word,dx ;CS_CODE now points to
- mov gdt2.base_hi_byte,cl ; CSEG as a code segment
- mov gdt3.base_lo_word,dx ;CS_DATA now points to
- mov gdt3.base_hi_byte,cl ; CSEG as a data segment
-
- mov dx,ss ;form 24bit address out of
- xor cx,cx ; SS:0000
- call form_24bit_address
- mov gdt4.base_lo_word,dx ;SS_DESC now points to
- mov gdt4.base_hi_byte,cl ; stack segment
-
- lgdt gdt ;Load the GDTR
-
- mov ah,enable_bit20 ;gate address bit 20 on
- call gate_a20
- or al,al ; was the command accepted?
- jz m_10 ; go if yes
- mov dx,offset gate_failure ;print error msg
- mov ah,9 ; and terminate
- int 21h
- int 20h
-
- gate_failure db "Address line A20 failed to Gate open$"
-
- m_10: cli ;No interrupts
-
- in al,inta01 ;get status of Int Controller #1
- mov i8259_1,al
- in al,intb01 ;get status of Int Controller #2
- mov i8259_2,al
-
- ASSUME ds:bios_data_seg
- mov dx,bios_data_seg ;Real Mode Return address
- mov ds,dx
- mov io_rom_seg,cs
- mov io_rom_init,offset real
-
- mov al,shut_down ;Set shutdown byte
- out cmos_port,al ; to shut down x05.
- jmp short $+2 ;I/O delay
- mov al,5
- out cmos_port+1,al
-
- mov ax,virtual_enable ;machine status word needed to
- lmsw ax ;switch to virtual mode
- jumpfar m_20,cs_code ;Must purge prefetch queue
-
- m_20: ASSUME ds:cseg ;IN VIRTUAL MODE ...
- mov ax,ss_desc ;stack segment selector
- mov ss,ax ;user's ss+sp is not a descriptor
-
- mov ax,cs_data
- mov ds,ax ;DS = CSEG as data
-
- mov gdt5.base_lo_word,0000h ;use 8000 for COLOR
- mov gdt5.base_hi_byte,0Bh
- mov gdt6.base_lo_word,0000h
- mov gdt6.base_hi_byte,0Bh
-
- mov ax,ds_desc
- mov ds,ax
- mov ax,es_desc
- mov es,ax
- mov cx,80*25
- xor si,si
- xor di,di
- m_30: lodsw
- mov ah,70h ;attribute reverse video
- stosw
- loop m_30
-
- mov al,shut_cmd ;shutdown cmd
- out status_port,al ;get back into REAL mode
- m_40: hlt
- jmp short m_40
-
- SUBTTL Gate A20
- PAGE
- ;--------------------------------------------------------------:
- ; GATE_A20 :
- ; This routine controls a signal which gates address bit 20. :
- ; The gate A20 signal is an output of the 8042 slave processor.:
- ; Address bit 20 should be gated on before entering protected :
- ; mode. It should be gated off after entering real mode from :
- ; protected mode. :
- ; Input: (AH)=0DDh addr bit 20 gated off (A20 always 0) :
- ; (AH)=0DFh addr bit 20 gated on (286 controls A20) :
- ; Output: (AL)=0 operation successful. 8042 has accepted cmd :
- ; (AL)=2 Failure -- 8042 unable to accept command. :
- ;--------------------------------------------------------------:
- gate_a20 PROC
- cli ;disable ints while using 8042
- call empty_8042 ;insure 8042 input buffer empty
- jnz gate_a20_01 ;ret if 8042 unable to accept cmd
- mov al,0D1h ;8042 command to write output port
- out status_port,al ;output cmd to 8042
- call empty_8042 ;wait for 8042 to accept command
- jnz gate_a20_01 ;ret if 8042 unable to accept cmd
- mov al,ah ;8042 port data
- out port_a,al ;output port data to 8042
- call empty_8042 ;wait for 8042 to port data
- gate_a20_01:
- ret
- gate_a20 ENDP
- ;--------------------------------------------------------------:
- ; EMPTY_8042 :
- ; This routine waits for the 8042 buffer to empty :
- ; Input: None :
- ; Output: (AL)=0 8042 input buffer empty (ZF=1) :
- ; (AL)=2 Time out, 8042 buffer full (ZF=0) :
- ;--------------------------------------------------------------:
- empty_8042 PROC
- push cx ;save CX
- sub cx,cx ;CX=0 will be the time out value
- empty_8042_01:
- in al,status_port ;read 8042 status port
- and al,00000010b ;test input buffer full flag (D1)
- loopnz empty_8042_01 ;loop until input buffer empty
- ; or time out
- pop cx ;restore CX
- ret
- empty_8042 ENDP
-
- SUBTTL form_24bit_address
- PAGE
- ;--------------------------------------------------------------:
- ; FORM_24BIT_ADDRESS :
- ; Input: DX has some segment :
- ; CX has some offset :
- ; Output: DX has base_lo_word :
- ; CL has base_hi_byte :
- ;--------------------------------------------------------------:
- form_24bit_address PROC
- push ax
- ;DX == s15 s14 s13 s12 s11 ... s04 s03 s02 s01 s00
- rol dx,4
- ;DX == s11 ... s04 s03 s02 s01 s00 s15 s14 s13 s12
- mov ax,dx
- ;AX == s11 ... s04 s03 s02 s01 s00 s15 s14 s13 s12
- and dl,0F0h
- ;DX == s11 ... s04 s03 s02 s01 s00 0 0 0 0
- and ax,0Fh
- ;AX == 0 ... 0 0 0 0 0 s15 s14 s13 s12
- add dx,cx ;form_24bit_address
- mov cx,ax ;get base_hi_byte in CL
- adc cl,ch ;carry in (CH=0)
- pop ax
- ret
- form_24bit_address ENDP
-
- SUBTTL Real Mode re-entry point.
- PAGE
- ASSUME ds:cseg ;IN REAL MODE ...
-
- real: mov dx,cs
- mov ds,dx ;DS = CS
- mov ah,disable_bit20 ;gate address bit 20 on
- call gate_a20
- mov al,i8259_1
- out inta01,al ;set status of Int Controller #1
- mov al,i8259_2
- out intb01,al ;set status of Int Controller #2
-
- sti ;turn the interrupts on
- int 20h ;back to DOS
-
- main ENDP
- cseg_leng EQU $
- cseg ENDS
- END start