; Listing 1 -- Entering Protected Mode ; ;----------------------------------------------------------------------------- ; ; TSPEC_A1.L1 Copyright (c) 1991, 1995 Robert Collins ; ; You have my permission to copy and distribute this software for ; non-commercial purposes. Any commercial use of this software or ; source code is allowed, so long as the appropriate copyright ; attributions (to me) are intact, *AND* my email address is properly ; displayed. ; ; Basically, give me credit, where credit is due, and show my email ; address. ; ;----------------------------------------------------------------------------- ; ; Robert R. Collins email: rcollins@metronet.com ; 7201 Avalon Dr. ; Plano, TX 75025 ; ;----------------------------------------------------------------------------- ;---------------------------------------------------------------; ; BEGIN LISTING 1 ; ;---------------------------------------------------------------; ; Equates & local variables ; ;---------------------------------------------------------------; ; Shown here for reference, but defined in TSPEC_A1.ASM ; ;---------------------------------------------------------------; ; Mstrmsk equ 021h ; 8259 master mask addr ; ; Slv_msk equ 0a1h ; 8259 slave mask addr ; ; KBC_CTL equ 060h ; 8042 control port ; ; KBC_STAT equ 064h ; 8042 status port ; ; Cmos_index equ 070h ; CMOS address port ; ; Cmos_data equ 071h ; CMOS data port ; ; Shut_down equ 00fh ; CMOS index for shutdwn; ; Type5 equ 5 ; Shutdown type-5 ; ; enable_bit20 equ 0dfh ; enable A20 command ; ; inpt_buf_full equ 2 ; Input buffer full ; ; ; ; ; ;---------------------------------------------------------------; ; Macro definitions ; ;---------------------------------------------------------------; ; Shown here for reference, but defined in TSPEC_A1.ASM ; ;---------------------------------------------------------------; ;Io_delay macro ; ; out 0edh,ax ;; about 1uS delay ; ; endm ; ; ; ; ; ;---------------------------------------------------------------; ; External segments ; ;---------------------------------------------------------------; ; Shown here for reference, but defined in TSPEC_A1.ASM ; ;---------------------------------------------------------------; ;ABS0 SEGMENT AT 0 ; ; org 0467h ; ; PM_Ret_off dw ? ; PM ret addr offset ; ; PM_Ret_seg dw ? ; PM ret addr segment ; ;ABS0 ENDS ; ; ; ; ; ;---------------------------------------------------------------; ; Data segment ; ;---------------------------------------------------------------; ; Shown here for reference, but defined in TSPEC_A1.ASM ; ;---------------------------------------------------------------; ;_DATA SEGMENT WORD PUBLIC 'DATA' ; ; i8259_1 db ? ; Status for master device ; ; i8259_2 db ? ; Status of slave device ; ;_DATA ENDS ; ; ; ; ; ;_TEXT SEGMENT WORD PUBLIC 'CODE' ; ; ASSUME CS:_TEXT, DS:_DATA, ES:_DATA, SS:NOTHING ; ;---------------------------------------------------------------; ; SETPM_RET_ADDR: Save the real-mode return address @ 40:67 ; from protected mode. ;--------------------------------------------------------------- ; Input: CS:AX = Return address from PM. ; DS = Better darn well have a PM segment selector! ; (Or else Kablooie!) ; Output: None ; Register(s) modified: None ;--------------------------------------------------------------- Setpm_ret_addr proc near ;--------------------------------------------------------------- push dx ; save it push ds mov dx,ABS0 ; mov ds,dx ASSUME DS:ABS0 mov DS:PM_Ret_off,ax mov DS:PM_Ret_seg,cs ASSUME DS:_DATA pop ds pop dx ret Setpm_ret_addr endp ;--------------------------------------------------------------- ; Get_INT_status: Saves the master and slave mask register ; contents from the 8259 interrupt controller. ;--------------------------------------------------------------- ; Input: DS = _DATA SEGMENT ; Output: i8259_1 = Status of master device ; i8259_2 = Status of slave device ; Register(s) modified: None ;--------------------------------------------------------------- Get_int_status proc near ;--------------------------------------------------------------- push ax in al,mstrmsk ; get master PIC mask mov i8259_1,al IO_Delay ; I/O delay in al,slv_msk ; get slave PIC mask mov i8259_2,al pop ax ret ; exit Get_int_status endp ;--------------------------------------------------------------- ; SET_SHUTDOWN_TYPE: Set the processor shutdown type-5 in CMOS. ;--------------------------------------------------------------- ; Input: None ; Output: None ; Register(s) modified: None ;--------------------------------------------------------------- Set_shutdown_type proc near ;--------------------------------------------------------------- pushf ; save interrupt status cli ; disable ints so somebody else ; doesn't do this right now push ax mov al,shut_down ; Set shutdown byte out cmos_index,al ; to shut down x05. IO_Delay ; I/O delay mov al,Type5 ; out cmos_data,al ; CMOS data port pop ax popf ret set_shutdown_type endp ;--------------------------------------------------------------- ; CALC_PM_ADDRESS: Calculate 32-bit protected mode address. ; Used for building descriptor tables. ;--------------------------------------------------------------- ; Input: ES:SI = Real mode address ; Output: DX:AX = 32-bit linear address ; Register(s) modified: AX, DX ;--------------------------------------------------------------- Calc_pm_address proc near ;--------------------------------------------------------------- mov ax,es ; point to control block xor dh,dh ; clear upper register mov dl,ah ; build high byte of 32-bit addr shr dl,4 ; use only high nibble from (AX) shl ax,4 ; strip high nibble from segment add ax,si ; add GDT offset for low word adc dx,0 ; adj high byte if CY from low ret ; back to calling program calc_pm_address endp ;--------------------------------------------------------------- ; Enable_gate20: Turn on A20, and check for errors. ;--------------------------------------------------------------- ; Input: None ; Output: CY=ERROR ; Register(s) modified: None ;--------------------------------------------------------------- Enable_gate20 proc near ;--------------------------------------------------------------- push ax mov ah,enable_bit20 ; gate address bit 20 on Call Gate_A20 or al,al ; command accepted? jz A20_OK ; go if yes stc ; set error flag A20_OK: pop ax ret ; exit Enable_gate20 endp ;--------------------------------------------------------------- ; GATE_A20: This routine controls a signal which gates address ; line 20 (A20). The gate A20 signal is an output of ; of the 8042 slave processor (keyboard controller). ; A20 should be gated on before entering protected ; mode, to allow addressing of the entire 16M address ; space of the 80286, or 4G address space of the ; 80386 & 80486. It should be gated off after ; entering real mode -- from protected mode. ;--------------------------------------------------------------- ; Input: AH = DD ==> A20 gated off (A20 always 0) ; AH = DF ==> A20 gated on (CPU controls A20) ; Output: AL = 0 ==> Operation successful ; AL = 2 ==> Operation failed, 8042 can't accept cmd ; Register(s) modified: AX ;--------------------------------------------------------------- Gate_a20 proc near ;--------------------------------------------------------------- pushf ; save interrupt status cli ; disable ints while using 8042 Call Empty_8042 ; insure 8042 input buffer empty jnz A20_Fail ; ret: 8042 unable to accept cmd IO_Delay ; I/O Delay mov al,0D1h ; 8042 cmd to write output port out KBC_STAT,al ; output cmd to 8042 Call Empty_8042 ; wait for 8042 to accept cmd jnz A20_Fail ; ret: 8042 unable to accept cmd mov al,ah ; 8042 port data out KBC_CTL,al ; output port data to 8042 Call Empty_8042 ; wait for 8042 to port data push cx ; save it mov cx,14h ; @DLY: IO_Delay ; Wait for KBC to execute the loop @DLY ; command. (about 25uS) pop cx ; restore it A20_Fail: popf ; restore flags 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 ; AL = 2, Time out; 8042 buffer full: NZ ; Register(s) modified: AX ;--------------------------------------------------------------- Empty_8042 proc near ;--------------------------------------------------------------- push cx ; save CX xor cx,cx ; CX=0: timeout value Try_KBC: IO_Delay ; in al,KBC_STAT ; read 8042 status port and al,inpt_buf_full; input buffer full flag (D1) loopnz Try_KBC ; loop until input buffer empty ; or timeout pop cx ; restore CX ret Empty_8042 endp ;--------------------------------------------------------------- ; END LISTING 1 ;---------------------------------------------------------------