;       SCCSID = @(#)testcfga.asm       6.1 92/01/09
        page    56,79

;*** TESTCFGA.ASM - TestCFG Device Driver
;*
;*      IBM Confidential
;*
;*      Copyright (c) IBM Corporation 1987, 1992
;*
;*      All Rights Reserved
;*
;*   DESCRIPTION
;*
;*     TESTCFG assembly routines.  Mostly workers for TESTCFG C code.
;*
;*   MODIFICATION HISTORY
;*
;* 6.1  01/15/92 CP20 B731???  Jeff Muir         Original Version
;* 6.2  05/12/94 R207  83779   Frank Schroeder   Fixed IsAPMPresent()
;*      09/17/94 RBDD  98451   Jon Grimm         Resource Manager
;*      03/30/95               C.Coy/E.Coy       Include IBM 486SLC fix
;*      05/08/96               F.Schroeder Added IEEE-1284 Query Device ID
;*

; include definitions for DEVHLP and macros
include testcfga.inc

.286c
;
;       C Startup routine for OS/2 Device Drivers
;
;  1.   Provides the user's "main" routine with the address of
;       the request packet.
;
;  2.   Defines the segments in the proper order (data, then code)
;       so if testcfga.obj is included first in the link line, the
;       segments for the device driver will be ordered correctly.
;
;  3.   Satisfies the C EXTRN for __acrtused, which prevents the startup
;       logic from being included from the standard C library.

        EXTRN   _main:near
        EXTRN   _Device_Help:dword
        PUBLIC  _STRATEGYCFG
        PUBLIC  __acrtused

_DATA   segment word public 'DATA'
_DATA   ends

IDATA   segment word public 'DATA'
IDATA   ends

CONST   segment word public 'CONST'
CONST   ends

_BSS    segment word public 'BSS'
_BSS    ends

RMCode          segment word public 'CODE'
RMCode          ends

Code            segment word public 'CODE'
Code            ends

STATICCODE      segment word public 'CODE'
STATICCODE      ends

_TEXT           segment word public 'CODE'
_TEXT           ends

INITCODE        segment word public 'CODE'
INITCODE        ends

SWAPCODE        segment word public 'CODE'
SWAPCODE        ends

DGROUP  group   CONST, _BSS, _DATA, IDATA

StaticGroup     group   RMCode, Code, STATICCODE, INITCODE
SWAPGROUP       group   SWAPCODE, _TEXT

IDATA       SEGMENT

.286p

            public selectorTable
            public IDT_SEL

align       4
selectorTable LABEL  DWORD              ; local GDT selector tables
IDT_SEL     DW     0

align       4
            PUBLIC IDTR
            PUBLIC szIDT
IDTR        LABEL  FWORD
szIDT       DW     0                    ;size of IDT
pIDT        DD     0                    ;linear address of IDT

align       4
o_trp6          dd      ?
o_trp6_p4       dd      ?

LDTINFO     DW     0                      ; Local info segment selector

timer_run    db    0           ;flag when timer tick has run
IDATA       ENDS


STATICCODE segment word public 'CODE'

          assume        cs:STATICCODE, ds:DGROUP, es:NOTHING
__acrtused equ 1

_STRATEGYCFG proc  far

          push  es      ; &reqpacket.hi
          push  bx      ; &reqpacket.lo
          call  _main
          pop   bx
          pop   es
          mov   word ptr es:[bx+3],ax  ; plug in status word
          ret

_STRATEGYCFG endp

;----------------------------------------------------------------------------:
;                                                                            ;
;   BOOL  ProcRun( ULONG EventId, PUSHORT AwakeCount);                       ;
;                                                                            ;
;----------------------------------------------------------------------------;
EventId     equ word ptr [bp+nbase]
AwakeCount  equ dword ptr [bp+nbase+4]

NCPROC   _ProcRun
        push    es
        push    bx
.386
        mov     bx, EventId[0]
        mov     ax, EventId[2]

        mov     dl,DevHlp_ProcRun                ; Select function
        call    [_Device_Help]                   ; Call devhelp

        les     bx, AwakeCount
        mov     es:[bx], ax
.286c
        pop     bx
        pop     es
ENDNCPROC _ProcRun


STATICCODE  ends

SWAPCODE segment word public 'CODE'
          assume        cs:SWAPCODE, ds:DGROUP, es:NOTHING

;---------------------------------------------------------------------------
; FUNCTION : InB - input byte from port
;---------------------------------------------------------------------------
NCPROC   _InB

        push    dx                      ; save registers
        mov     dx,word ptr [bp+nbase]   ; get I/O address
        in      al,dx                   ; read from the port
                                        ; (AL) - Port value
        pop     dx                      ; restore registers

ENDNCPROC _InB

;---------------------------------------------------------------------------
; FUNCTION : OutB - Output byte to port
;---------------------------------------------------------------------------
NCPROC   _OutB

        push    dx                      ; save registers
        mov     dx,word ptr [bp+nbase]   ; get I/O address
        mov     al,byte ptr [bp+nbase+2] ; get I/O value
        out     dx,al                   ; write to the port
        pop     dx                      ; restore registers

ENDNCPROC _OutB

;---------------------------------------------------------------------------
; FUNCTION : InW - Input word from port
;---------------------------------------------------------------------------
NCPROC   _InW

        push    dx                      ; save registers
        mov     dx,word ptr [bp+nbase]   ; get I/O address
        in      ax,dx                   ; read from the port
                                        ; (AX) - Port value
        pop     dx                      ; restore registers

ENDNCPROC _InW

;---------------------------------------------------------------------------
; FUNCTION : OutW - Output word to port
;---------------------------------------------------------------------------
NCPROC   _OutW
        push    dx                      ; save registers
        mov     dx,word ptr [bp+nbase]   ; get I/O address
        mov     ax,word ptr [bp+nbase+2] ; get I/O value
        out     dx,ax                   ; write to the port
        pop     dx                      ; restore registers


ENDNCPROC _OutW

;---------------------------------------------------------------------------
; FUNCTION : InDW - Input DWord from port
;---------------------------------------------------------------------------
NCPROC   _InDW

.386
        mov     dx,word ptr [bp+nbase]    ; get I/O address
        in      eax,dx                   ; read from the port
                                         ; (EAX) - Port value
        mov     edx,eax                  ; (AX) - low port value
        shr     edx,16                   ; (dx)
.286c

ENDNCPROC _InDW

;---------------------------------------------------------------------------
; FUNCTION : OutDW - Output DWord to port
;---------------------------------------------------------------------------
NCPROC   _OutDW

        push    dx                        ; save registers
        mov     dx,word ptr [bp+nbase]     ; get I/O address
.386
        mov     eax,dword ptr [bp+nbase+2] ; get I/O value
        out     dx,eax                    ; write to the port
.286c
        pop     dx                        ; restore registers

ENDNCPROC _OutDW

;---------------------------------------------------------------------------
; FUNCTION : strlen - determine length of string
;---------------------------------------------------------------------------
NCPROC   _strlen

        push    si                              ; save register

        mov     si,word ptr [bp+nbase]           ; (SI) String Offset
        xor     ax,ax                           ; (AX) String Length
sl10:
        cmp     byte ptr [si],0                 ; Is character zero?
        je      slx                             ; yes, end of string
        inc     ax                              ; increase count of chars
        inc     si                              ; move to next char
        jmp     sl10                            ;
slx:
        pop     si                              ; restore register

ENDNCPROC _strlen


;***************************************************************************
; DevHelp Code 15h
;
; FUNCTION
;
; PhysToVirt - Map Physical Address to Virtual Address
;
; DESCRIPTION
;
; In the OS/2 Mode, PhysToVirt converts a 32-bit address to a valid
; selector-offset pair.  In the DOS mode, PhysToVirt converts a 32-bit
; address to a segment-offset pair.
;
; C PROTOCOL
;
; USHORT PhysToVirt(ULONG PhysAddr,USHORT Length,PULONG VirtAddr)
;***************************************************************************
; parameter equates
PTV_PhysAddrLow    equ    word ptr [bp+nbase]
PTV_PhysAddrHigh   equ    word ptr [bp+nbase+2]
PTV_Length         equ    word ptr [bp+nbase+4]
PTV_VirtAddr       equ    dword ptr [bp+nbase+6]

NCPROC   _PhysToVirt
        push    dx                               ; Save registers
        push    cx
        push    bx
        push    di
        push    si
        push    ds
        push    es
        mov     bx,PTV_PhysAddrLow               ; low physical address
        mov     ax,PTV_PhysAddrHigh              ; high physical address
        mov     cx,PTV_Length                    ; length
        mov     dh,1                             ; result
        mov     dl,DevHlp_PhysToVirt             ; Select function
        call    [_Device_Help]                   ; Call devhelp
        jc      ptv10
        mov     dx,es
        les     bx,PTV_VirtAddr                  ; address of VirtAddr
        mov     word ptr es:[bx],di
        mov     word ptr es:[bx+2],dx
        xor     ax,ax
        jmp     ptv20
ptv10:
        mov     ax,1
ptv20:
        pop     es
        pop     ds
        pop     si
        pop     di
        pop     bx
        pop     cx
        pop     dx
ENDNCPROC _PhysToVirt

;***************************************************************************
; DevHelp Code 27h
;
; FUNCTION
;
; VerifyAccess - Verify Access to Memory
;
; DESCRIPTION
;
; This routine verifies that the user process has the correct access rights
; for the memory that it passed to the device driver. If the process does
; not have the needed access rights to the memory, then it will be
; terminated.  If it does have needed access rights, these rights are
; guaranteed to remain valid until the device driver exits its strategy
; routine.
;
; C PROTOCOL
;
; USHORT VerifyAccess(PUCHAR pMem,USHORT MemLen,USHORT AccType);
;***************************************************************************
; parameter equates
VA_pMemOff  equ         word ptr [bp+nbase]
VA_pMemSeg  equ         word ptr [bp+nbase+2]
VA_MemLen   equ         word ptr [bp+nbase+4]
VA_AccType  equ         byte ptr [bp+nbase+6]

NCPROC   _VerifyAccess
        push    dx                               ; Save register
        push    cx
        push    di
        mov     ax,VA_pMemSeg                    ; Segment
        mov     cx,VA_MemLen                     ; Length of memory area
        mov     di,VA_pMemOff                    ; Offset to memory area
        mov     dh,VA_AccType                    ; Type of Access (0 R, 1 R/W)
        mov     dl,DevHlp_VerifyAccess           ; Select function
        call    dword ptr [_Device_Help]         ; Call devhelp
        jc      va10
        xor     ax,ax
        jmp     vax
va10:   or      ax,1
vax:
        pop     di
        pop     cx
        pop     dx                               ; Restore register
ENDNCPROC _VerifyAccess


;***************************************************************************
; DevHelp Code 32h
;
; FUNCTION
;
; UnPhysToVirt - Mark Completion of Virtual Address Use
;
; DESCRIPTION
;
; UnPhysToVirt is required to mark completion of address conversion from
; VirtToPhys
;
; C PROTOCOL
;
;   void UnPhysToVirt(void);
;***************************************************************************
NCPROC   _UnPhysToVirt
        push    dx                               ; Save register
        mov     dl,DevHlp_UnPhysToVirt           ; Select function
        call    dword ptr [_Device_Help]         ; Call devhelp
        pop     dx                               ; Restore register
ENDNCPROC _UnPhysToVirt

;----------------------------------------------------------------------------:
;                                                                            ;
;   BOOL ProcBlock( ULONG EventId, ULONG WaitTime, USHORT IntWaitFlag );     ;
;                                                                            ;
;----------------------------------------------------------------------------;
EventID     equ   word ptr [bp+nbase]
WaitTime    equ   word ptr [bp+nbase+4]
IntWaitFlag equ   word ptr [bp+nbase+8]

NCPROC   _ProcBlock
        push    bx
        push    cx
        push    dx
        push    di
        push    si
.386
        mov     bx, EventId[0]
        mov     ax, EventId[2]
        mov     cx, WaitTime[0]
        mov     di, WaitTime[2]
        mov     dx, IntWaitFlag
        mov     dh, dl
        mov     dl,DevHlp_ProcBlock              ; Select function
        call    [_Device_Help]                   ; Call devhelp
.286c
        pop     si
        pop     di
        pop     dx
        pop     cx
        pop     bx

ENDNCPROC _ProcBlock

;***************************************************************************
;
; FUNCTION
;
; IsAPMPresent
;
; DESCRIPTION
;
; This routine determines if Advanced Power Management BIOS is present.
; This routine returns true only when either 16-bit or 32-bit protect
; mode APM BIOS is found.  When only real mode APM BIOS is found, this
; routine returns false.
;
; C PROTOCOL
;
; INT    IsAPMPresent(VOID);
;***************************************************************************

FCPROC   _IsAPMPresent
        push    bx
        push    cx
        push    dx
        push    ds

        xor     cx, cx                           ; cx=0, just query APM,
                                                 ; don't establish connection
        mov     al, 16                           ; index 16 (APM info)
        mov     dl, DevHlp_GetDOSVar             ; select function
        call    [_Device_Help]                   ; call devhelp
        jc      short no_apm                     ; error, return 0

        push    ax
        pop     ds
        test    WORD PTR ds:[bx].APM_Flags, 03h  ; 16-bit or 32-bit PM APM?
        jz      short no_apm                     ; no, return 0 (no apm)
        mov     ax, 1                            ; otherwise return 1 (apm)
        jmp     short apm_exit

no_apm:
        xor     ax, ax
apm_exit:
        pop     ds
        pop     dx
        pop     cx
        pop     bx

ENDFCPROC _IsAPMPresent

;***************************************************************************
;
; FUNCTION
;
; GetDCTable - Get DASD Device Class table
;
; DESCRIPTION
;
; This routine is used to get the DASD device class table.
;
; C PROTOCOL
;
; USHORT GetDCTable(PVOID &(DCPtr);
;***************************************************************************
; parameter equates
GDV_DCPtr  equ     word ptr [bp+nbase] ; address to place Device Class Table

NCPROC   _GetDCTable
        push    dx                             ; Save registers
        push    cx
        push    bx
        push    es

        mov     ax,14                          ; Index (Device Class Table)
        mov     cx,1                           ; DASD device class
        mov     dl,DevHlp_GetDosVar            ; Select function
        call    [_Device_Help]                 ; Call devhelp
        jc      gdv10                          ; ax:bx ptr to table
        mov     dx,bx                          ;
        mov     bx,GDV_DCPtr
        mov     ds:[bx],dx                     ; fill in DCPtr (return it)
        mov     ds:[bx+2],ax
        xor     ax,ax
        jmp     gdv_x
gdv10:
        mov     ax,1
gdv_x:
        pop     es
        pop     bx
        pop     cx
        pop     dx
ENDNCPROC _GetDCTable

;-----------------------------------------------------;
; VOID _ZeroCB (PBYTE ControlBlock, USHORT Length)    ;
;                                                     ;
; Function: Zero fill the input control block         ;
;                                                     ;
;-----------------------------------------------------;
CtrlBlk EQU dword ptr [bp+nbase]
BlkLen  EQU  word ptr [bp+nbase+4]

NCPROC   _ZeroCB


        push    es
        push    bx
        push    cx
        push    di
.386
        xor     eax,eax
        les     di,CtrlBlk
        mov     cx,BlkLen
        mov     bx,cx
        and     bx,3
        shr     cx,2
        cmp     cx,0
        je      zcb_rem
        rep     stosd

zcb_rem:
        mov     cx,bx
        cmp     cx,0
        je      zcb_ret
        rep     stosb

zcb_ret:
.286c
        pop     di
        pop     cx
        pop     bx
        pop     es

ENDNCPROC _ZeroCB

;----------------------------------------------------------;
; VOID _BlockCopy (PBYTE Dest, PBYTE Orig, USHORT Length   ;
;                                                          ;
; Function: Copy a block of data                           ;
;                                                          ;
;----------------------------------------------------------;
BlkDest  EQU dword ptr [bp+nbase]
BlkSrc   EQU dword ptr [bp+nbase+4]
BlkCLen  EQU  word ptr [bp+nbase+8]

NCPROC   _BlockCopy

        push    ds
        push    es
        push    di
        push    si
        push    cx
        push    bx
.386
        les     di,BlkDest
        lds     si,BlkSrc
        mov     cx,BlkCLen

        mov     bx,cx
        and     bx,3
        shr     cx,2
        cmp     cx,0
        je      bc_rem
        rep     movsd

bc_rem:
        mov     cx,bx
        cmp     cx,0
        je      bc_ret
        rep     movsb

bc_ret:
.286c
        pop     bx
        pop     cx
        pop     si
        pop     di
        pop     es
        pop     ds

ENDNCPROC _BlockCopy


SWAPCODE  ends


INITCODE        segment word public 'CODE'

          assume        cs:INITCODE, ds:DGROUP, es:NOTHING
;***************************************************************************
; FUNCTION
;
; SegLimit - determine segment limit
;
; DESCRIPTION
;
; Returns the current limit of the requested segment.
;
;***************************************************************************
NCPROC   _SegLimit

        push    es
        push    bx
        push    di
        mov     ax, word ptr [bp+nbase]
;       lsl     bx, ax                       ; get segment limit
        db      0fh,03,0d8h
        les     di, dword ptr [bp+nbase+2]    ; address of limit var
        mov     word ptr es:[di],bx
        xor     ax,ax

        pop     di
        pop     bx
        pop     es

ENDNCPROC _SegLimit

;***************************************************************************
; DevHelp Code 16h
;
; FUNCTION
;
; VirtToPhys - Map Virtual Address to Physcial Address
;
; DESCRIPTION
;
; VirtToPhys converts a selector-offset pair to a 32-bit address.
;
; C PROTOCOL
;
; USHORT VirtToPhys(ULONG VirtAddr,PULONG pPhysAddr)
;***************************************************************************
; parameter equates
VTP_VirtAddr       equ    dword ptr [bp+nbase]
VTP_pPhysAddr      equ    dword ptr [bp+nbase+4]

NCPROC   _VirtToPhys
        push    dx                               ; Save registers
        push    cx
        push    bx
        push    di
        push    si
        push    ds
        push    es
.386
        lds     si,VTP_VirtAddr
        mov     dl,DevHlp_VirtToPhys             ; Select function
        call    [_Device_Help]                   ; Call devhelp
        jc      vtp10
        les     di,VTP_pPhysAddr                  ; address of PhysAddr
        mov     word ptr es:[di],bx
        mov     word ptr es:[di+2],ax
        xor     ax,ax
        jmp     vtp20
vtp10:
        mov     ax,1
vtp20:
.286c
        pop     es
        pop     ds
        pop     si
        pop     di
        pop     bx
        pop     cx
        pop     dx
ENDNCPROC _VirtToPhys

;***************************************************************************
; DevHelp Code 34h
;
; FUNCTION
;
; GetLIDEntry - Get a Logical ID
;
; DESCRIPTION
;
; This routine is used to obtain a Logical ID (LID) for devices that exist
; (that is, devices that are awake).
;
; C PROTOCOL
;
;   USHORT GetLIDEntry(USHORT DeviceID,USHORT RelativeLID,USHORT DeviceState,
;                      PUSHORT pLID);
;***************************************************************************
; parameter equates
GL_DeviceID    equ        byte ptr [bp+nbase]
GL_RelID       equ        byte ptr [bp+nbase+2]
GL_DevState    equ        byte ptr [bp+nbase+4]
GL_pLID        equ        dword ptr [bp+nbase+6]

NCPROC   _GetLIDEntry
        push    dx                               ; Save registers
        push    es
        push    bx

        mov     al,GL_DeviceID                   ; DeviceID
        mov     bl,GL_RelID                      ; Relative LID
        mov     dh,GL_DevState                   ; Device State
        mov     dl,DevHlp_GetLIDEntry            ; Select function
        call    [_Device_Help]                   ; Call devhelp
        jc      gle10
        les     bx,GL_pLID                       ; Address of Var Addr
        mov     word ptr es:[bx],ax
        xor     ax,ax
gle10:
        pop     bx
        pop     es
        pop     dx
ENDNCPROC _GetLIDEntry

;***************************************************************************
; DevHelp Code 35h
;
; FUNCTION
;
; FreeLIDEntry - Release a Logical ID
;
; DESCRIPTION
;
; This routine is used to release a Logical ID.  This must be done at
; DEINSTALL or termination time.
;
; C PROTOCOL
;
; USHORT FreeLIDEntry(USHORT LID);
;***************************************************************************
; parameter equates
FL_LID  equ     word ptr [bp+nbase]

NCPROC   _FreeLIDEntry
        push    dx                               ; Save registers

        mov     ax,FL_LID                        ; LogicalID
        mov     dl,DevHlp_FreeLIDEntry           ; Select function
        call    [_Device_Help]                   ; Call devhelp
        jc      fle10
        xor     ax,ax
fle10:
        pop     dx
ENDNCPROC _FreeLIDEntry

;***************************************************************************
; DevHelp Code 36h
;
; FUNCTION
;
; ABIOSCall - Invoke ABIOS Function
;
; DESCRIPTION
;
; This routine is used to invoke an ABIOS service for the Operating
; System Transfer Convention.
;
; C PROTOCOL
;
; USHORT ABIOSCall(USHORT LID, POINTER RBOffset, USHORT Entry);
;***************************************************************************
; Parameter equates
AB_LID        equ   word ptr [bp+nbase]
AB_RBOffset   equ   word ptr [bp+nbase+2]
AB_Entry      equ   byte ptr [bp+nbase+4]

NCPROC   _ABIOSCall
        push    dx                               ; Save registers
        push    si

        mov     ax,AB_LID                        ; LogicalID
        mov     si,AB_RBOffset                   ; RB Offset
        mov     dh,AB_Entry                      ; Entry
        mov     dl,DevHlp_ABIOSCall              ; Select function
        call    [_Device_Help]                   ; Call devhelp
        jc      abc10
        xor     ax,ax
abc10:
        pop     si
        pop     dx
ENDNCPROC _ABIOSCall


;***************************************************************************
; SlcWarp trap 6 handler
;
; FUNCTION
;
; trap6     - Called by hardware if trap on "Write MSR" instruction
;
; DESCRIPTION
;
; This routine is used to catch invalid instruction traps in the SlcWarp
; subroutine, in particular the invalid instruction trap when writing
; to the MSR (no MSRs on 486s other than the IBM 486SLC).
;
;***************************************************************************
align       4
trap6       proc   far

;------------------------------------------------------------------------------
;       setup a stack frame and make return pointer return to 4th instruction
;       following the faulting opcode
;------------------------------------------------------------------------------
            push   bp
            mov    bp,sp
            mov    ax,ss:[bp+2]
            add    ax,2
            mov    ss:[bp+2],ax
            mov    sp,bp
;;int 3
            pop    bp
            iret
trap6       endp

;***************************************************************************
; SlcWarp timer handler
;
; FUNCTION
;
; timer     - Called by OS/2 on a timer tick
;
; DESCRIPTION
;
; This routine is used once during the initialization call to SlcWarp.
; The timer hook is used to get a routine running at ring 0 during the
; init call (which runs at ring 3).
;
;***************************************************************************
align       4
timer       proc   far
.386p
            pushad
            push   ds
            push   es
            mov    ax,SEG IDTR
            mov    ds,ax
            mov    es,ax             ; ds and es to my data segment
            call   phase2            ; start second phase of installation
            mov    ax,SEG IDATA
            mov    ds,ax
;;int 3
            mov    timer_run,1       ; timer has run

            pop    es
            pop    ds
            popad
            ret
timer       endp

;***************************************************************************
; SlcWarp phase 2
;
; FUNCTION
;
; phase2    - Called by timer
;
; DESCRIPTION
;
; This routine is used once during the initialization call to SlcWarp.
; This routine is called out of the timer hook (see routine 'timer')
; so it is running at ring 0.  This routine will set up the trap 6 handler,
; attempt to write the IBM 486SLC Machine Specific Register that has the
; bad silicon fix (the "Fox-Pro bit"), and return.
;
;***************************************************************************

align       4
phase2      proc   near

            lea    ax,timer          ; take my code out of timer link
            mov    dl,DevHlp_ResetTimer
            call   [_Device_Help]    ; Call devhelp
;------------------------------------------------------------------------------
;           map IDT into my GDT selectors
;------------------------------------------------------------------------------
.386p
            sidt   IDTR
            mov    ebx, dword ptr pIDT
            mov    ecx,0
            mov    cx,szIDT
            inc    cx
            mov    ax,[IDT_SEL]
            mov    dl,DevHlp_LinToGDTSelector
            call   [_Device_Help]    ; Call devhelp
            jc     lx

;------------------------------------------------------------------------------
;           Now.. put my NMI routine in IDT
;------------------------------------------------------------------------------
            mov    ax,[IDT_SEL]      ; point into IDT
            mov    es,ax
            mov    bx,6*size IGD     ; point to trap 6 (sixth descriptor)

            ;   ********** save original trap 6 vector *******
                mov     eax,es:[bx]
                mov    o_trp6,eax
                mov     eax,es:[bx+4]
                mov    o_trp6_p4,eax
           ;    **********************************************

            mov    ax,offset TRAP6
            mov    es:[bx].Off_0_15,ax
            mov    ax,SEG TRAP6
            mov    es:[bx].SegSel,ax
            mov    al,es:[bx].access
            and    al,11110000b
            or     al,6
            mov    es:[bx].access,al


;------------------------------------------------------------------------------
;       write MSR 1004 bit 29 to disable FOX-Pro logic
;------------------------------------------------------------------------------

         mov    eax,0000H             ; set EAX to 0
         mov    edx,0000H             ; set EDX to 0
         mov    ecx,0000H             ; set ECX to 0
         mov     eax,20000000h        ; undo Foxpro fix
         mov    ecx,0000H             ; set ECX to 0
         mov     ecx,1004h            ; point to msr 1004

        db      0FH,30H               ; Write the msr
        nop                           ;required because two byte opcode
                                      ;trashes this next byte of code
        nop             ;invalid opcode trap (int 6) handler returns here
        nop
        nop


            ;   ********** restore original trap 6 vector *******
.386p
                mov    eax,o_trp6_p4
                mov     es:[bx+4],eax
                mov    eax,o_trp6
                mov     es:[bx],eax
           ;    **********************************************

lx:
            ret
phase2      endp

;***************************************************************************
; IBM 486SLC fix routine
;
; FUNCTION
;
; SlcWarp   - Correct IBM 486SLC hardware bug
;
; DESCRIPTION
;
; This routine is used to set the machine state register on the IBM
; 486SLC chip.  A number of these chips had a silicon bug that caused
; faults during OS/2 install (and perhaps other places on levels of
; OS/2 before Warp!).
;
; C PROTOCOL
;
; USHORT SlcWarp();
;***************************************************************************

NCPROC      _SlcWarp

;------------------------------------------------------------------------------
;           Allocate GDT selectors for later use
;------------------------------------------------------------------------------

            mov    ax,SEG selectorTable
            mov    es,ax
            lea    di, selectorTable
            mov    cx,1                    ; allocate 1 GDT selector
            mov    dl,DevHlp_AllocGDTSelector
            call   [_Device_Help]    ; Call devhelp

            jc     finished          ; allocation ok or error

;------------------------------------------------------------------------------
;           Skip if this is not a 486
;------------------------------------------------------------------------------
            call   GetProcessorType            ; check for > 486
            cmp    ax,0008H
            jne    finished                          ; Not a 486, skip it!

;------------------------------------------------------------------------------
;           Intall my timer routine. Used to gain level 0 functions
;------------------------------------------------------------------------------

            lea    ax,timer
            mov    dl,DevHlp_SetTimer
            call   [_Device_Help]    ; Call devhelp
            jc     finished

;------------------------------------------------------------------------------
;       WAIT FOR TIMER TO RUN
;------------------------------------------------------------------------------
timer_wait:
;;int 3
timer_loop:
; use a spin loop to wait for the timer to run
; (would have used a semaphore, but the table "DevHlp Services and
; Device Contexts" in the PDD Reference for OS/2 implies that
; semaphores are not available at PDD Init time...)
            cmp    timer_run,1
            jne    timer_loop

finished:
ENDNCPROC   _SlcWarp

;************************************************************************
;                                                                       *
; GetProcessorType - Determine type of CPU processor                    *
;                                                                       *
;       Entry:  none                                                    *
;                                                                       *
;       Exit:   AX = bit flag result                                    *
;                    001h = Intel 8086                                  *
;                    002h = Intel 80286                                 *
;                    004h = Intel 80386                                 *
;                    008h = Intel 80486                                 *
;                    010h = Intel 80586 PENTIUM                         *
;                                                                       *
; Copyright (c) Distributed Processing Technology 1993                  *
;                                                                       *
;************************************************************************

        public GetProcessorType

GetProcessorType   proc near
        push    bx
        push    dx
        push    di

        mov     ax, 1                   ; Default to 8086

Check8086:
        pushf                           ; Preserve original flags
        pushf                           ;
        pop     bx                      ; Get flags into BX

        and     bx, 0FFFh               ;
        push    bx                      ;
        popf                            ; 8086 will leave the top bits
        pushf                           ;  of the flags rgister set.
        pop     bx                      ;
        and     bx, 0F000h              ;
        popf                            ; Restore original flags

        cmp     bx, 0F000h              ; If bits 12-15 were on then its
        je      ProcTypeSet             ;   an 8088 or 8086

Check80286:
        mov     ax, 2                   ; Set to atleast a 80286

        pushf                           ; Preserve original flags
        mov     bx, 7000h               ;
        push    bx                      ; Try to set the NT and IOPL,
        popf                            ;  if it can be done then it's
        pushf                           ;  a 386 or higher.
        pop     bx                      ;
        popf                            ; Restore original flags
        and     bh, 70h
        jz      short ProcTypeSet

Check80386:
        mov     eax, 3                  ; Set to atleast a 80386

        push    ebx
        mov     edx, esp
        and     esp, 0FFFFFFFch         ; Prevent stack alignment fault.
        pushfd                          ; Preserve original flags

        pushfd                          ;
        pop     ebx                     ;
        or      ebx, 40000h             ; If we can set the AC bit in the
        push    ebx                     ;  flags register then it's a 486.
        popfd                           ;
        pushfd                          ;
        pop     ebx                     ;

        popfd                           ; Restore original flags.
        mov     esp, edx                ; Restore stack pointer.
        test    ebx, 40000h             ;
        pop     ebx
        jz      short ProcTypeSet       ; It's a 80386

Check80486:
        mov     eax, 4                  ; Set to atleast a 80486

        push    ebx                     ; SAVE EBX
        pushfd                          ; Get current flags
        pop     ebx                     ;
        mov     edx, ebx                ;
        xor     ebx, 200000h            ; attempt to toggle ID bit
        push    ebx                     ;
        popfd                           ;
        pushfd                          ;
        pop     ebx                     ;

        push    edx                     ;
        popfd                           ; Restore original flags.
        and     ebx, 200000h            ;
        and     edx, 200000h            ; If we cannot toggle the bit then
        cmp     ebx, edx                ;   it's a ONLY A 80486!
        pop     ebx                     ; RESTORE EBX
        je      short ProcTypeSet       ;

        mov     eax, 1                  ; Use the CPUID command to the
        db      0Fh, 0A2h               ;  processor family level.
        shr     eax, 8                  ;  5 = 586 or Pentium
        and     ax, 0Fh                 ;  6 = 686 or Sexium
                                        ;  etc.
ProcTypeSet:
        dec     ax                      ; 01 = Intel 8086
        mov     cl, al                  ; 02 = Intel 80286
        mov     ax, 01                  ; 04 = Intel 80386
        shl     ax, cl                  ; 08 = Intel 80486
        pop     di                      ; 10 = Intel 80586 PENTIUM
        pop     dx
        pop     bx
        ret
GetProcessorType   endp


INITCODE        ends

          end
