;       SCCSID = @(#)ibmnmi.asm	6.3 92/03/16
SCCSID  equ     "@(#)ibmnmi.asm	6.3 92/03/16"
PAGE    ,132
NAME    IBMNMI
TITLE   IBM NMI Manager

;**     NMI
;
;
;       DESCRIPTION
;
;       The NMI Manager is designed to initialize NMI handling
;       on machines using ABIOS, and provides a central location
;       for disable and enable nmi functions.
;
;       This is IBM Unique code
;
;       WARNING
;
;       It is not possible to disable DMA or Watchdog Timeouts using
;       disableNMI function.  Also, if an NMI occurs on planar memory,
;       it is not possible to clear the condition on some machines, so
;       NMI should remain disabled after calling ABIOS.
;
;       NMI occurences are only handled by the NMI Manager in PROTECT MODE
;
;
;       MODIFICATION HISTORY:
;
;

.xlist
        include dosseg.inc
        include basemaca.inc
        include osmaca.inc
        include fnotask.inc
        include mhandle.inc
        include mi.inc
        include pmode.inc
        include struc.inc
        include pgexport.inc
        include vmexport.inc          ; Defs for SELAllocKHB
        include vmowner.inc           ; Memory ownership definitions
        include osconst.inc

.list


        include nmi.inc
        include basemid.inc

;       ReferGlobal     ABIOS_present,BYTE      ;will be defined by sysinit

        EXTRN           ABIOSCall:NEAR

;;;     EXTRNFAR        SegAlloc
        EXTRNFAR        ABIOSCall
        EXTRNFAR        GetLIDEntry
        EXTRNFAR        SelToSeg
        extrn           _SELAllocKHB:near


        ModName  ,FNO_IBMNMI_ASM
        CpuMode 386                     ; Here goes nothing!

          FARCODE INIT
INITCODE segment

ASSUME  DS:ABIOSDATA


;/********************** START OF SPECIFICATIONS *********************/
;/*                                                                  */
;/* SUBROUTINE NAME:  IBMInitNMI                                     */
;/*                                                                  */
;/* DESCRIPTIVE NAME:  Initialize NMI Manager                        */
;/*                                                                  */
;/* FUNCTION: This routine is called by NMI.ASM to initialize        */
;/*           the NMI Manager.  When Running on with ABIOS, this     */
;/*           involves initializing ABIOS NMI Interrupt handling.    */
;/*                                                                  */
;/* NOTES:                                                           */
;/*         Protect Mode only  (System Initialization time)          */
;/*                                                                  */
;/* ENTRY POINT: InitNMI                                             */
;/*    LINKAGE: Call Near                                            */
;/*                                                                  */
;/* INPUT:                                                           */
;/*      none                                                        */
;/*                                                                  */
;/* EXIT-NORMAL:   cf = 0                                            */
;/*                ax = 0                                            */
;/*                                                                  */
;/* EXIT-ERROR:    cf = 1  Unable to initialize NMI Handler          */
;/*                        (ABIOS initialization error for NMI)      */
;/*                ax =    Error_Cannot_Init_NMI                     */
;/* EFFECTS:                                                         */
;/*      All registers saved except AX                               */
;/*                                                                  */
;/* INTERNAL REFERENCES:                                             */
;/*                                                                  */
;/*                ABIOSRB                                           */
;/*                NMIDevice                                         */
;/*                NMILID                                            */
;/*                NMIParm                                           */
;/*                RB_Selector                                       */
;/*                RB_Segment                                        */
;/*                                                                  */
;/*    ROUTINES:                                                     */
;/*      none                                                        */
;/*                                                                  */
;/* EXTERNAL REFERENCES:                                             */
;/*                                                                  */
;/*                ABIOS_present                                     */
;/*                                                                  */
;/*                                                                  */
;/*    ROUTINES:                                                     */
;/*                ABIOSCall          (When using ABIOS)             */
;/*                GetLIDEntry        (When using ABIOS)             */
;/*                HandleGetInfo      (When using ABIOS)             */
;/*                SegAlloc           (When using ABIOS)             */
;/*                                                                  */
;/*********************** END OF SPECIFICATIONS **********************/

Procedure  IBMInitNMI
LocalVar vmac,<SIZE VMAC>
        EnterProc


          SaveReg <bx,cx,dx,si,di,es>

          mov     al,NMIDevice            ; set for NMI device number
          xor     bl,bl                   ; get first LID
          xor     dh,dh                   ; reserved (0)

          CALLFAR GetLIDEntry             ; get Logical ID for NMI 'device'
          jc      err_j

          mov     NMILID,ax               ; save the LID in variable

          lea     si,ABIOSRB              ; Point to request block. Set up for
          xor     dh,dh                   ; Set for start entry point.

          mov     word ptr ds:[si].RBLength,size ABIOSRB
          mov     word ptr ds:[si].LogicalID,ax
          mov     word ptr ds:[si].Unit,0
          mov     word ptr ds:[si].Function,NMIParm
          mov     word ptr ds:[si].RBFlags,0
          mov     word ptr ds:[si].ReturnCode,0ffffh


          CALLFAR ABIOSCall               ; Get LID Parameters
err_j:    jnc     noerr
          jmp     err
noerr:

;        Allocate the memory
;        rc = _SELAllocKHB(heap hdl, size, flags, selflags, hobowner, &address)

          movzx   ecx,[si].NMIRBLength    ; grab the ABIOS Request Block size
          FlatContext <ds,es>,eax         ; set up for C calls
          SSToDS  eax,vmac

          CCALL32 _SELAllocKHB,<VM_HKH_PUB_RES1MRW, ecx, \
                                <VMAC_ALIGNPARA+PG_RESIDENT+PG_U+PG_CONTIG>, \
                                <D_DATA+D_DPL0>, NMIOWNER, eax>

          or      ax,ax
          jnz     err                     ; did the SegAlloc fail?
          mov     bx,vmac.ac_sel          ; BX = SEL

          DosContext      <ds>

          mov     RB_Selector,bx          ; place selector into variable

          CALLFAR SelToSeg                ; Get segment pointer to RBs
          jc      err

          mov     RB_Segment,ax           ; place segment into variable


                                          ; set up Request blocks
          mov     si,0
          mov     es,RB_Selector

setup:

          mov     ax,size ABIOSRB
          mov     word ptr es:[si].RBLength,ax
          mov     ax,NMILID
          mov     word ptr es:[si].LogicalID,ax
          mov     word ptr es:[si].Unit,0
          mov     word ptr es:[si].RBFlags,0

          xor     dh,dh                   ; Set for Start Entry Point
          mov     si,NMIRBL

          mov     ax,NMILID                          ; ax gets LID
          mov     bx,NMICRead
          sub     bx,IntVal
          mov     ds,RB_Selector                     ; Point to Request Block
          mov     word ptr ds:[si].Function,bx
          mov     word ptr ds:[si].ReturnCode,0ffffh

          CALLFAR ABIOSCall               ; Start ABIOS NMI Handling
          mov     ax,0
          jnc     all_done


err:      stc
          mov     ax,MSG_SYSINIT_NOT_INIT_NMI
          Panic <"IBMInitNMI">  ; BUGBUG - until caller acts on error return


all_done:

          RestoreReg <es,di,si,dx,cx,bx>
          LeaveProc
          ret


EndProc    IBMInitNMI


INITCODE ends


        FARCODE LOW
ABIOSCODE SEGMENT

ASSUME  DS:ABIOSDATA

;/********************** START OF SPECIFICATIONS *********************/
;/*                                                                  */
;/* SUBROUTINE NAME:  EnableNMI                                      */
;/*                                                                  */
;/* DESCRIPTIVE NAME:  Enable NMI                                    */
;/*                                                                  */
;/* FUNCTION:  This routine enables the maskable events of NMI at    */
;/*            the hardware when ABIOS is not in the system, or calls*/
;/*            the ABIOS enable NMI function when ABIOS is present.  */
;/*                                                                  */
;/* NOTES:  NONE                                                     */
;/*                                                                  */
;/* ENTRY POINT: IBMEnableNMI                                        */
;/*    LINKAGE: near                                                 */
;/*                                                                  */
;/* INPUT:                                                           */
;/*      none                                                        */
;/*                                                                  */
;/* EXIT-NORMAL:  CF = 0                                             */
;/*                                                                  */
;/* EXIT-ERROR:   CF = 1  Unable to complete enable operation        */
;/*                                                                  */
;/* EFFECTS:                                                         */
;/*     none                                                         */
;/*                                                                  */
;/* INTERNAL REFERENCES:                                             */
;/*                                                                  */
;/*               Enable                                             */
;/*               NMILID                                             */
;/*               NMI_PORT                                           */
;/*               RB_Segment                                         */
;/*               RB_Selector                                        */
;/*               NMIEnab                                            */
;/*                                                                  */
;/*                                                                  */
;/*    ROUTINES:                                                     */
;/*     none                                                         */
;/*                                                                  */
;/* EXTERNAL REFERENCES:                                             */
;/*                                                                  */
;/*               ABIOS_present                                      */
;/*                                                                  */
;/*    ROUTINES:                                                     */
;/*                                                                  */
;/*               ABIOSCall         (when using ABIOS)               */
;/*                                                                  */
;/*********************** END OF SPECIFICATIONS **********************/


Procedure  IBMEnableNMI,near


          mov     ax,NMILID                  ; Use the NMI Logical ID
          xor     si,si                      ; use first request block
          xor     dh,dh                      ; use the start entry point

          whatmode                        ; are we in protect mode?

          .if     nc
            mov     ds,RB_Segment           ; load DS with segment for RB

          .else
            mov     ds,RB_Selector          ; load DS with Selector for RB

          .endif


          mov     ds:[si].Function1,NMIEnab  ; set up for the enableNMI
          mov     word ptr ds:[si].ReturnCode,0ffffh

          call    ABIOSCall

          ret

EndProc    IBMEnableNMI

;/********************** START OF SPECIFICATIONS *********************/
;/*                                                                  */
;/* SUBROUTINE NAME:  IBMDisableNMI                                  */
;/*                                                                  */
;/* DESCRIPTIVE NAME:  Disable NMI                                   */
;/*                                                                  */
;/* FUNCTION:  This routine disables the maskable events of NMI at   */
;/*            the hardware when ABIOS is not in the system, or calls*/
;/*            the ABIOS disable NMI function when ABIOS is present. */
;/*                                                                  */
;/* NOTES:                                                           */
;/*            It is not possible to disable DMA timeout or          */
;/*            Watchdog timeout with this function.                  */
;/*                                                                  */
;/* ENTRY POINT: IBMDisableNMI                                       */
;/*    LINKAGE:  Near                                                */
;/*                                                                  */
;/* INPUT:                                                           */
;/*      none                                                        */
;/*                                                                  */
;/* EXIT-NORMAL:  CF = 0                                             */
;/*                                                                  */
;/* EXIT-ERROR:   CF = 1  Unable to complete disable operation       */
;/*                                                                  */
;/* EFFECTS:                                                         */
;/*      none                                                        */
;/*                                                                  */
;/* INTERNAL REFERENCES:                                             */
;/*                                                                  */
;/*               NMILID                                             */
;/*               NMI_PORT                                           */
;/*               RB_Segment                                         */
;/*               RB_Selector                                        */
;/*               NMIDisab                                           */
;/*               Disable                                            */
;/*                                                                  */
;/*    ROUTINES:                                                     */
;/*      none                                                        */
;/*                                                                  */
;/* EXTERNAL REFERENCES:                                             */
;/*     none                                                         */
;/*                                                                  */
;/*    ROUTINES:                                                     */
;/*               ABIOScall                                          */
;/*                                                                  */
;/*********************** END OF SPECIFICATIONS **********************/


Procedure  IBMDisableNMI,near

          mov     ax,NMILID                  ; Use the NMI Logical ID
          xor     si,si                      ; use first request block
          xor     dh,dh                      ; use the start entry point


          whatmode                        ; are we in protect mode?

          .if     nc
            mov     ds,RB_Segment           ; load DS with segment for RB

          .else
            mov     ds,RB_Selector          ; load DS with Selector for RB

          .endif


          mov     ds:[si].Function1,NMIDisab ; set up for the DisableNMI
          mov     word ptr ds:[si].ReturnCode,0ffffh

          call    ABIOSCall

        ret


EndProc    IBMDisableNMI


ASSUME  DS:ABIOSDATA

;/********************** START OF SPECIFICATIONS *********************/
;/*                                                                  */
;/* SUBROUTINE NAME:  IntNMI                                         */
;/*                                                                  */
;/* DESCRIPTIVE NAME:  NMI Interrupt Handler for using ABIOS         */
;/*                                                                  */
;/* FUNCTION: This routine is called from the NMI interrupt          */
;/*           handler to service the NMI using ABIOS routines.       */
;/*                                                                  */
;/* NOTES:                                                           */
;/*         This is a protect mode only routine called at            */
;/*         interrupt time.                                          */
;/*                                                                  */
;/* ENTRY POINT: IBMIntNMI                                           */
;/*    LINKAGE: Call Near                                            */
;/*                                                                  */
;/* INPUT:                                                           */
;/*      none                                                        */
;/*                                                                  */
;/* EXIT-NORMAL:                                                     */
;/*              cf = 0                                              */
;/*              AX = index of cause of NMI                          */
;/*                   1  - Memory Parity                             */
;/*                   2  - Channel Check                             */
;/*                   3  - DMA Bus Timeout                           */
;/*                   4  - Watchdog Timeout                          */
;/*                                                                  */
;/* EXIT-ERROR:                                                      */
;/*      none                                                        */
;/*                                                                  */
;/* EFFECTS:                                                         */
;/*                                                                  */
;/*      DH and SI registers                                         */
;/*                                                                  */
;/* INTERNAL REFERENCES:                                             */
;/*                                                                  */
;/*                NMILID                                            */
;/*                NMIType                                           */
;/*                RB_Selector                                       */
;/*                                                                  */
;/*    ROUTINES:                                                     */
;/*      none                                                        */
;/*                                                                  */
;/* EXTERNAL REFERENCES:                                             */
;/*    ROUTINES:                                                     */
;/*                ABIOSCall                                         */
;/*                                                                  */
;/*********************** END OF SPECIFICATIONS **********************/


Procedure  IntNMI,far16

;       PMONLY
        push ds
        DosContext <ds>

        mov     ax,NMILID
        mov     si,NMIRBL               ; use the second (interrupt time) RB
        mov     ds,RB_Selector          ; Load DS with selector for RB
        mov     dh,01H                  ; use the interrupt entry point

        CALLFAR ABIOSCall               ; call the ABIOS interrupt handler

        mov     ax,[si].NMIType
        pop     ds

        RETP


EndProc    IntNMI

ABIOSCODE  ENDS

ABIOSDATA    SEGMENT

NMILID          dw    ?
NMIRBL          dw    ?
RB_Segment      dw    ?
RB_Selector     dw    ?
NMICRead        dw    4752H

ABIOSRB         db    size RB0 dup (0)

ABIOSDATA    ENDS

        END
