;       SCCSID = @(#)abioinit.asm       6.10 92/03/11
TITLE   ABioInit - ABios initialization code
PAGE    ,132

SCCSID  equ     "@(#)abioinit.asm       6.10 92/03/11"

;                 IBM/Microsoft Confidential
;
;           Copyright (c) IBM Corporation  1987, 1990
;           Copyright (c) Microsoft Corp.  1987, 1990
;                     All Rights Reserved

;
; SOURCE FILE NAME:     ABIOINIT.ASM
;
; DESCRIPTIVE NAME:     ABIOS System Initialization
;
; FUNCTION:
;
;       This module contains the routines called to initalize the ABIOS
;       Common Data Areas. The following picture depicts the final
;       layout of the ABIOS data structures when initialization is complete.
;
;        +----------------------------------------------------------+
;        |                   DOS Low Memory Data                    |
;        |  Real Mode Anchor                    Protect Mode Anchor |
;        |         |                                     |          |
;        +---------|-------------------------------------|----------+
;                  |                                     |
;                  |                                     |
;    +-------------+-----------------+       +-----------+-------------------+
;    |                               |       |                               |
;    |       Real Mode               |       |       Protect Mode            |
;    |                               |       |                               |
;    |       Common Data Area        |       |       Common Data Area        |
;    |                               |       |                               |
;    |                               |       |                               |
;    |                               |       |                               |
;    +-------------------------------+       +-------------------------------+
;    |                               |       |                               |
;    |       Real Mode FTTs          |       |       Protect Mode FTTs       |
;    |                               |       |                               |
;    +-------------------------------+       +-------------------------------+
;    |                               |       |       Above 1M                |
;    |       Dual Mode DBs           |       +-------------------------------+
;    |                               |
;    +-------------------------------+
;    |       Below 1M                |
;    +-------------------------------+
;
;
; NOTES:
;    DEPENDENCIES:
;       To be called from System Initialization after physical memory management
;       has been initialized. Must execute in a code segment below 1M since we
;       use mode switching.
;
;    RESTRICTIONS:
;       The Common Data Areas, Device Blocks, and Function Transfer Tables are
;       aligned on 4 byte boundaries for 386 fetch performance.
;
; ENTRY POINTS:
;               syiABiosInit
;
; EXTERNAL REFERENCES:
;       SYIOpenFile
;       SYIReadFile
;       SYICloseFile
;       ProtModeIC
;       RealModeIC
;       AllocateGDTSelector
;       FreeGDTSelector
;       PhysToGDTSelector
;       SegAlloc
;       SegFree
;       MemAlloc
;       SelToSeg
;       SetDescInfo
;       INT 15h
;       WrtToScrn
;       InternalError
;       GDTAlloc
;       GDTFree
;

.xlist
include dosseg.inc
include basemaca.inc
include fnoinit.inc
include osmaca.inc
include mhandle.inc
include mi.inc
include pmode.inc
include struc.inc
include config.inc
include inisms.inc
include basemid.inc
include osconst.inc
include pgexport.inc
include vmexport.inc
include selxport.inc
include abios.inc
include abioflag.inc
include infoseg.inc
include doshlp.inc            ; DosHlp's info
.list

        ModName  , FNO_ABIOINIT_ASM
        CpuMode 386

        ReferGDT        GDT_RM_IDT,WORD

        ReferGlobal     SISData,BYTE
        ReferGlobal     ABIOS_Revision,BYTE
        ReferGlobal     DevConfigTbl
        ReferGlobal     ABIOS_CDA_anchor_p,WORD
        ReferGlobal     ABIOS_CDA_anchor_r,WORD
        ReferGlobal     ABIOS_System_Parameter_Table,BYTE
        ReferGlobal     ProtSegSize,WORD
        ReferGlobal     RealCDASel,WORD
        ReferGlobal     RealInitDS,WORD

        ReferInitGlobal OEM_config,WORD
        EXTRNFAR        AllocateGDTSelector
        EXTRNFAR        FreeGDTSelector
        EXTRNFAR        PhysToGDTSelector
        EXTRNFAR        SegAlloc
        EXTRNFAR        SegFree
        EXTRNFAR        SelToSeg
        EXTRNFAR        SetDescInfo
        EXTRNFAR        GDTAlloc
        EXTRNFAR        GDTFree
        EXTRNFAR        GetDescInfo

        extrn   _VMDonateKHB:near
        extrn   _SELFreeKHB:near                        ; ** dcr 660
        extrn   _SELAllocKHB:near                       ; ** dcr 660
        extrn   ProtModeIC:near
        extrn   RealModeIC:near
        extrn   SYICloseFile:near
        extrn   SYIOpenFile:near
        extrn   SYIReadFile:near
        extrn   SYISaveMessage:near
        extrn   SYIAbort:near
        EXTRN           _VMAllocMem:near
        EXTRN           _VMFreeMem:near
        EXTRN           _VMLinToPhys:near
ifdef PMDEBUG
        extrn   InitComPort:far
endif



LF      equ     10
CR      equ     13
EOF     equ     1ah
PATCH_BUFFER_SIZE       equ     20480

DATA segment

;
;       RAM Patch Specification FIle Name
;

FName   db      'ABIOS.SYS',0
wildcardroutine dd      0               ; patch file install (yes/no) routine
public fIBMSystem    ;D90588
fIBMSystem      dw      0               ; IBM or OEM system unit
                                        ;           OEM = CFG_OEM_ABIOS
DATA ends                               ;           IBM = CFG_IBM_ABIOS

;
;       Protect Mode Selector Allocation Table Entry Structure
;

SelTblEntry     struc
SelTblSel       dw      0       ; Selector
SelTblSeg       dw      0       ; Segment
SelTblLimit     dw      0       ; Limit
SelTblAccess    dd      0       ; Access Rights
SelTblEntry     ends

;
;       Global Descriptor Table Register Structure
;

GDTReg_s        struc
GDTRegLimit     dw      0       ; Limit
GDTRegLaddrl    dw      0       ; Low word of base address (linear)
GDTRegLaddrh    dw      0       ; High word of base address (linear)
GDTReg_s        ends


INITDATA segment
;
;       Data For RAM Patch Area Information and Missing Patch File Message
;

PatchErrMsg     SMT     <MSG_SYSINIT_SFILE_NOT_FND,1>
                SMT_Var <0>

ABIOSPatchArea_Laddrl   dd      ?
ABIOSPatchArea_Laddrh   dd      ?
ABIOSPatchArea_Paddrl   dd      ?
ABIOSPatchArea_Paddrh   dd      ?
ABIOSPatchArea_GDTReg   dw      ?

rampatchcopyright       db      "(C) Copyright IBM Corporation"
rpcopyrightlen          EQU     $ - rampatchcopyright
systemcopyright1        db      "COPR. IBM 1981"
syscopyright1len        EQU     $ - systemcopyright1
systemcopyright2        db      "CCOOPPRR..  IIBBMM  11998811"
syscopyright2len        EQU     $ - systemcopyright2
systemcopyright3        db      "C) IBM CORP. 1981"             ; P75 ROM
syscopyright3len        EQU     $ - systemcopyright3
INITDATA ends


INITBSS segment
;
;       Table for Protect Mode Selector Allocation Tracking
;

                public  ABIOSSelTable
                public  ABIOSSelTableEnd
SELTBLSIZE      equ     50

ABIOSSelTable   db      (size SelTblEntry * SELTBLSIZE) dup (0)

ABIOSSelTableEnd        label   byte

;temporary gdt selector
gdtsel          dw      ?
INITBSS ends


        FARCODE INIT
INITCODE segment

;***LP  syiABiosInit - ABIOS Initialization
;
;       Set up system for ABIOS usage.
;
;       ENTRY   NONE
;       EXIT    Carry Flag *clear* if ABIOS initialized correctly
;               Carry Flag *set*   if ABIOS did not initialize correctly
;       EFFECTS System prepared for ABIOS operation.
;
;       Called from DosInit after memory manager has been initialized. Must be
;       called in Protect Mode. The code segment this is in must be < 1M since
;       mode switching is used to accomplish the initialization.
;
;       1) Do Real Mode Initialization (syiABiosRealInit).
;       2) Do Protect Mode Initialization (syiABiosProtInit).

Procedure syiABiosInit,faronly
assume  ds:NOTHING, es:NOTHING, ss:NOTHING

;       PMONLY

        call    syiABiosRealInit
        cli
        .if <nc>
          call    syiABiosProtInit
          clc
        .endif

        ret

EndProc syiABiosInit



;***LP  syiABiosRealInit - ABIOS Real Mode Initialization
;
;       Build the Real Mode Common Data Area.
;
;       ENTRY   NONE
;       EXIT    Carry Flag *clear* if ABIOS initialized correctly
;               Carry Flag *set*   if ABIOS did not initialize correctly
;       EFFECTS
;           Real Mode CDA constructed.
;           DOSGROUP:ABIOS_CDA_anchor_r initialized.
;           DOSGROUP:RealCDASel initialized.
;           DOSGROUP:ProtSegSize = Size needed for ABIOS Protect Mode Segment
;
;       Builds the Real Mode Common Data Area in a low memory segment. This
;       routine is called ONLY and when ABIOS IS PRESENT !!!
;       The following steps are executed:
;
;       1) Load any RAM Patches (LoadRAMPatch).
;       2) Build the System Intialization Table
;       3) Allocate Memory for the Initialization Table (SegAlloc).
;       4) Build the Initialization Table.
;       5) Scan the Initialization Table to determine control
;          block area sizes
;       6) Allocate Memory for the Real Mode ABIOS Segment (SegAlloc)
;       7) Build the Common Data Area, FTTs, and DBs, for Real Mode

Procedure syiABiosRealInit,,local
assume ds:nothing,es:nothing,ss:nothing
        LocalVar        _LIDS,WORD              ; # LIDS for CDA
        LocalVar        _FTTBYTES,WORD          ; # bytes for FTTs
        LocalVar        _DPBYTES,WORD           ; # bytes for Data Pointers
        LocalVar        _DBBYTES,WORD           ; # bytes for DBs
        LocalVar        _CDAEND,WORD            ; Offset of CDA End
        LocalVar        _FTTOFF,WORD            ; Offset of FTT storage
        LocalVar        _DBOFF,WORD             ; Offset of DB storage
        LocalVar        _BASELID,WORD           ; BASELID for CDA Build Loop
        LocalVar        _NUMENTRY,WORD          ; NUM InitTbl Entries
        LocalVar        _IT_SEG,WORD            ; InitTable Segment
        LocalVar        _IT_SEL,WORD            ; InitTable Selector
        LocalVar        _PATCH_PARA,WORD        ; RAM Patch Segment
        LocalVar        _SAVE15,DWORD           ; Save INT 15 Vector
        LocalVar        _SAVE0E,DWORD           ; Save INT 15 Vector
        LocalVar        _SAVEDRV,BYTE           ; Save boot drive

        EnterProc
        pusha
        SaveReg         <ds,es>

        mov     _LIDS, 2                        ; Initialize Local Vars
        mov     _FTTBYTES, 0
        mov     _DPBYTES, 0
        mov     _DBBYTES, 0
        mov     _CDAEND, 0
        mov     _FTTOFF, 0
        mov     _DBOFF, 0
        mov     _BASELID, 0
        mov     _PATCH_PARA, 0

;
        push    ds
        DosContext      ds
        mov     ax,ds:[SISData].SIS_BootDrv
        pop     ds
        add     al,'A' - 1
        mov     _SAVEDRV, al
        .if             <_SAVEDRV ne 'A'>
          SaveReg         <ds,ecx>
          mov di,GSEL GDT_RM_IDT      ; beginning of IVT in Protect Mode
          mov ds,di
          mov ecx,ds:[54h]            ;
          mov _SAVE15,ecx             ;
          mov ecx,ds:[4*0eh]          ;
          mov _SAVE0E,ecx             ;
          RestoreReg      <ecx,ds>
        .endif

        call    SystemOwner                     ; IBM or OEM system unit
        .if     nz
          mov   fIBMSystem,CFG_OEM_ABIOS        ; OEM system unit ;D91506
        .else
          mov   fIBMSystem,CFG_IBM_ABIOS        ; IBM system unit ;D90588
        .endif

        call    LoadRAMPatch                    ; (ax) = patch paragraph

        mov     _PATCH_PARA, ax

;
;       Switch to real mode and build the System Parameter Table
;

        NullContext es

        call    RealModeIC

        ; WARNING: Don't change AX until after check below.
        mov     ds, ax
        DosContext      <es>

        ; On RAM-loaded ABIOS machines, make sure first patch is a
        ; system/control module.
        mov     fs,ES:[RealInitDS]     ; (fs) = DOSINITDATA paragraph
        assume  fs:DOSINITDATA
        test    fs:[OEM_config], CFG_ABIOS_PRESENT
        .if <z>                        ; RAM-loaded ABIOS machine?

           ; ABIOS patches to load?
           .if <ax e 0>
              NullContext  fs,di
              xor    ax,ax     ;set AX=0 so error path will be taken
              jmp    ari_10
           .endif

           ; Make sure first patch is a system/control module
           mov    ax,ds:[0].RamPatchExtLength
           mov    di,ds:[0].RamPatchInitRoutine
           .if    <ax l 6> or  ; if extension header isn't long enough
           .if    <di eq 0>    ; or init routine offset is NULL
              NullContext  fs,di
              xor    ax,ax     ;set AX=0 so error path will be taken
              jmp    ari_10
           .endif
        .endif
        NullContext  fs,di

        lea     di, DOSGROUP:ABIOS_System_Parameter_Table
        mov     ah, ABIOS_Build_SPT
        int     15h                  ; warning - trashes bx on Canary
        cli

        .if c or
        .if <ah ne 0>
            push    ds
            mov     ds,ES:[RealInitDS]     ; (ds) = DOSINITDATA paragraph
            assume ds:DOSINITDATA
            test    ds:[OEM_config], CFG_ABIOS_PRESENT ;real error?
            .if <nz>
               InternalError   <ABiosRealInit:SysParmTable Build Failure>
            .endif
            ; maybe just RAM loaded ABIOS machine with wrong patches,
            ; just continue without ABIOS
            mov     ax,0        ; don't want to change flags with XOR.
            pop     ds
        .else

            mov     ax, es:[di].NumEntries          ; Set # of Entries
            mov     _NUMENTRY, ax
        .endif
;
;       Allocate Memory for the Initialization Table
;

ari_10:
        call    ProtModeIC
        .if     <ax e 0>
           jmp syiARI_error
        .endif
                                        ; (ax) = _NUMENTRY
        mov     dx, size IT_Entry
        mul     dx
        mov     bx, ax
        mov     ax, dx                  ; (ax:bx) = size of Initialization Table

        mov     cl, SA_GDT
        mov     ch, D_DATA0

        mov     si, HF_MOVABLE+HF_LOWMEM
        mov     di, ABIOSOWNER

        CALLFAR SegAlloc        ; (bx) = selector (ax) = handle
        .if c
                InternalError   <ABiosRealInit: SegAlloc Failed>
        .endif

        mov     _IT_SEL, bx

        CALLFAR SelToSeg        ; (ax) = paragraph on exit
        mov     _IT_SEG, ax

;
;       Switch to real mode and build the Initialization Table
;

        NullContext es
        NullContext ds

        call    RealModeIC

        mov     ds, _PATCH_PARA         ; (ds:0) = RAM PATCH AREA
        mov     es, ax                  ; (ax) = _IT_SEG
        xor     di, di                  ; (es:di) = Initialization Table
        mov     ah, ABIOS_Build_IT
        int     15h                     ; warning - trashes bx on Canary
        cli

        .if c or
        .if <ah ne 0>
                InternalError <Initialization Table Build Failure>
        .endif

;
;       Make 1st pass on Initialization Table to calculate CDA Table
;       Allocation Strategy.
;
;       CX = NUMENTRIES IN SYSTEM PARAMETER TABLE
;       ES:DI = INITIALIZATION TABLE BASE
;

        mov     cx, _NUMENTRY
        .repeat
                mov     dx, es:[di].DeviceCount
                add     _LIDS, dx
                mov     ax, es:[di].FTTLength
                add     _FTTBYTES, ax
                mov     ax, es:[di].DPLength
                add     _DPBYTES, ax

                mov     ax, es:[di].DBLength
                add     ax, 3           ; roundup to 4's
                and     ax, not 3

                mul     dx
                add     _DBBYTES, ax

                add     di, size IT_Entry
        .loop

;
;       Calculate offset of the end of the CDA.
;       Calculate the size needed for the Real Mode ABIOS Segment.
;

        mov     ax, _LIDS               ; (ax) = _LIDS
        shl     ax, 3                   ; (ax) = _LIDS*8
        add     ax, _DPBYTES            ; (ax) = (_LIDS*8) + DPBYTES
        add     ax, 2                   ; (ax) = (_LIDS*8) + DPBYTES + 2

        mov     _CDAEND, ax
        add     ax, 3           ; roundup to 4's
        and     ax, not 3

        add     ax, _FTTBYTES
        add     ax, _DBBYTES            ; (ax) = Real Mode ABIOS Seg Size

;
;       Allocate memory for the Real Mode ABIOS Segment and
;       Initialize the Real Mode Anchor.
;

        call    ProtModeIC

        mov     bx, ax
        xor     ax, ax          ; (ax:bx) = size of Real Mode ABIOS Seg

        mov     cl, SA_GDT
        mov     ch, D_DATA0

        mov     si, HF_FIXED+HF_LOWMEM+HF_ZEROINIT
        mov     di, ABIOSOWNER

        CALLFAR SegAlloc        ; (bx) = selector (ax) = handle

        .if c
                InternalError   <ABiosRealInit: SegAlloc Failed>
        .endif

        pushad
        mov     di, bx
        xor     dx, dx
;Returns limit to be donated in CX:DX
        CALLFAR GetDescInfo
        jc      cant_donate                      ; error
        movzx   eax, ax              ; set high word of base addr
        shl     eax, 16
        mov     ax,  bx              ; set low word of base addr

        movzx   ebx, cx              ; set high word of limit
        shl     ebx, 16
        mov     bx,  dx              ; set low word of limit

        add     eax, ebx             ; add limit to base addr

        mov     ebx, PAGESIZE        ; ebx = 1000 - (addr & 0xfff)
        mov     dx,  ax
        and     dh,  15
        movzx   edx, dx
        sub     ebx, edx

        FlatContext <ds,es>
        CCALL32 _VMDonateKHB <eax, ebx, PG_R>
        NullContext  <es>
cant_donate:
        popad

        SaveReg <bx>            ; Save selector
        CALLFAR SelToSeg        ; (ax) = segment paragraph on exit
        RestoreReg      <bx>    ; (bx) = selector to segment

        DosContext      <ds>
        mov     RealCDASel, bx
        mov     ABIOS_CDA_anchor_r, ax

        NullContext es

        call    RealModeIC

;
;       Setup local variables for CDA Build Loop. Install the
;       reserved fields into LID 0 in the CDA. Save the size
;       of the protect mode segment in DOSGROUP.
;

        mov     ds, ax                  ; (ds) = ABIOS_CDA_anchor_r

        mov     ax, _CDAEND
        sub     ax, 8                   ; Find DPOffset
        mov     ds:[0].CDADPOffset, ax  ; Set DPOffset in CDA

        mov     ax, _LIDS
        mov     ds:[0].CDALids, ax      ; Set # LIDS in CDA

        mov     ax, _CDAEND
        add     ax, 3                   ; roundup to 4's
        and     ax, not 3

        mov     _FTTOFF, ax
        add     ax, _FTTBYTES
        mov     _DBOFF, ax

        DosContext      <es>
        mov     es:ProtSegSize, ax

;
;       Loop to build the CDA.
;
;       (ax) = Scratch
;       (bx) = LIDPTR
;       (cx) = NUMENTRIES in System Parameter Table
;       (dx) = LIDCTR
;       (ds) = Real CDA Anchor
;       (es) = Initialization Table
;

        mov     es, _IT_SEG
        mov     dx, 2                   ; LIDCTR = 2 (Skip LID 0 & 1)
        mov     cx, _NUMENTRY
        xor     di, di                  ; (es:di) = Initialization Table

        .repeat
                SaveReg <cx>

                mov     _BASELID, dx    ; _BASELID = LIDCTR

                mov     cx, es:[di].DeviceCount

                .if ncxz near
                  .repeat
                          SaveReg <cx>

                          mov     bx, dx
                          shl     bx, 3

                          .if <es:[di].FTTLength eq 0>
                                mov     ds:[bx].FTTSegment, 0
                                mov     ds:[bx].FTTOffset, 0
                          .else
                                mov     ds:[bx].FTTSegment, ds
                                mov     si, _FTTOFF
                                mov     ds:[bx].FTTOffset, si
                          .endif

                          mov     ax, es:[di].DBLength
                          add     ax, 3                   ; roundup to 4's
                          and     ax, not 3

                          .if <ax eq 0>
                                mov     ds:[bx].DBSegment, 0
                                mov     ds:[bx].DBOffset, 0
                          .else
                                mov     ds:[bx].DBSegment, ds
                                mov     si, _DBOFF
                                mov     ds:[bx].DBOffset, si
                          .endif

                          add     _DBOFF, ax              ; next DB

                          inc     dx                      ; LIDCTR++
                          RestoreReg      <cx>
                  .loop

;
;       Call ABIOS to initialize FTTs, DBs, and DPs
;

                  SaveReg <dx>
                  mov     dx, _BASELID                    ; Get Starting LID
                  mov     cx, es:[di].DeviceCount         ; # DBs to Build

                  call    dword ptr es:[di].InitDB_XferPtr

;
;       NULL out the LID Entries for this Initialization Entry
;       and return the Device Block memory allocated.
;
                  .if <al ne 0>
                        .repeat
                                mov     bx, dx
                                shl     bx, 3

                                mov     ds:[bx].DBSegment, 0
                                mov     ds:[bx].DBOffset, 0

                                mov     ds:[bx].FTTSegment, 0
                                mov     ds:[bx].FTTOffset, 0

                                mov     si, es:[di].DBLength
                                add     si, 3
                                and     si, not 3
                                sub     _DBOFF, si

                                inc     dx
                        .loop

                  .else
                        mov     ax, es:[di].FTTLength
                        add     _FTTOFF, ax             ; Next FTT
                  .endif

                  RestoreReg      <dx>
                .endif

                add     di, size IT_Entry       ; Next IT_Entry

                RestoreReg      <cx>
                dec     cx
        .until <zero cx> near


        call    ProtModeIC
ifdef   PMDEBUG
        call    InitComPort
endif

        .if <_SAVEDRV ne 'A'>
          SaveReg         <ds,ecx>
          mov di,GSEL GDT_RM_IDT      ; beginning of IVT in Protect Mode
          mov ds,di
          mov ecx,_SAVE15             ;
          mov ds:[54h],ecx            ;
          mov ecx,_SAVE0E             ;
          mov ds:[4*0eh],ecx          ;
          RestoreReg      <ecx,ds>
        .endif

        mov     ax, _IT_SEL             ; Free the Initialization Table
        CALLFAR SegFree

        clc
        jmp syiARI_x

syiARI_error:
        stc

syiARI_x:

        RestoreReg <es,ds>
        popa
        LeaveProc
        ret
EndProc syiABiosRealInit


;***LP  SYIAllocSel - Setup a selector to a specifed physical address
;
;       Call VMAllocMem or GDTAlloc to get a selector to a specific
;       memory area.
;
;       Sets up selector by calling the proper routine based on whether the
;       paragraph address is page aligned (VMAllocMem) or not (GDTAlloc).
;
;       ENTRY   (AX)  = segment (paragraph address)
;               (EBX) = allocation flags
;               (ECX) = limit
;               (EDX) = selector flags
;       EXIT    Carry Flag clear on success
;                   (EBX) = linear address mapping segment
;                   (DI)  = selector mapping corresponding segment
;               Carry Flag set on error
;       USES    EBX, DI, Flags

Procedure SYIAllocSel
assume  ds:NOTHING, es:NOTHING, ss:NOTHING
        LocalVar        _BASE_SEG,WORD
        LocalVar ALLOC_BUFFER,<SIZE vmac_s> ; _VMAlloc buffer

        EnterProc       <ax>    ; _BASE_SEG
        SaveReg <es,ds>
        pushad
        test    ax,0ffh
        .if     <nz> near
;         paragraph address is not page aligned
          shl     eax,4
          DosInitContext <ds>
          .if     <eax ge ABIOSPatchArea_Paddrl> and
          .if     <eax lt ABIOSPatchArea_Paddrh>
;           paragraph address is within RAM patch area
            CALLFAR GDTAlloc
            mov     [ALLOC_BUFFER].ac_sel,ax
            mov     di,ax
            .if     <nc>
              mov     si,ABIOSPatchArea_GDTReg
              mov     es,si
              mov     es:[di].d_limit,cx
              movzx   eax,[_BASE_SEG]
              shl     eax,4
              sub     eax,ABIOSPatchArea_Paddrl
              add     eax,ABIOSPatchArea_Laddrl
              mov     [ALLOC_BUFFER].ac_va,eax
              mov     es:[di].d_loaddr,ax
              ror     eax,WORDSHIFT
              mov     es:[di].d_hiaddr,al
              mov     es:[di].d_extaddr,ah
              .if <ebx eq DATA_ALLOCF>
                mov     es:[di].d_access,D_DATA0
              .else
                mov     es:[di].d_access,D_CODE0
              .endif
              mov     es:[di].d_attr,0
              clc
              popad
              mov     di,ALLOC_BUFFER.ac_sel
              mov     ebx,ALLOC_BUFFER.ac_va
            .else
              InternalError   <SYIAllocSel:GDTAlloc failed>
            .endif
          .else
            InternalError   <SYIAllocSel:address not on 4k boundary>
          .endif
        .else
;         paragraph address is page aligned
          FlatContext <ds,es>,ax

;       rc = VMAllocMem(cb,cbcommit,fl,hptda,hobowner,hobmte,fselmgr,blkno,pac)
;
;       (EBX) = alloc flags
;       (ECX) = size
;       (EDX) = selector flags

          xor     eax,eax                 ; (EAX) = 0
          movzx   esi,[_BASE_SEG]         ; (EBX) = paddr
          shl     esi,4
          lea     di,[ALLOC_BUFFER]       ; Push flat address of return buffer
          movzx   edi,di
          SSToDS  edi
          CCALL32 _VMAllocMem,<ecx,ecx,ebx,eax,ABIOSOWNER,eax,edx,esi,edi>
          .if <zero eax>
            clc
            popad
            mov        di,ALLOC_BUFFER.ac_sel
            mov        ebx,ALLOC_BUFFER.ac_va
          .else
            stc
            popad
          .endif
        .endif
        RestoreReg <ds,es>
        LeaveProc
        ret
EndProc SYIAllocSel

;***LP  SYIFreeSel - Free a selector allocated by SYIAlloc_Free
;
;       Call VMFreeMem or GDTFree
;
;       Frees selector by calling the proper routine based on whether the
;       linear address is in the RAM patch area (GDTFree) or not (VMFreeMem).
;
;       ENTRY   (EBX) = Linear address
;               (DI)  = selector
;       EXIT    Carry Flag clear on success
;               Carry Flag set on error
;       USES    DS, Flags

Procedure SYIFreeSel
assume  ds:NOTHING, es:NOTHING, ss:NOTHING
        EnterProc
        SaveReg <es>
        pushad
        DosInitContext <ds>,ax
        .if     <ebx ge ABIOSPatchArea_Laddrl> and
        .if     <ebx lt ABIOSPatchArea_Laddrh>
;         linear address is within RAM patch area
          mov     ax,di
          CALLFAR GDTFree
        .else
;         linear address is not within RAM patch area
          FlatContext <ds,es>,ax

;       rc = VMFreeMem(laddr, hobptda, fl)

          CCALL32 _VMFreeMem,<ebx,0,0>    ; Release memory if error occurred
          .if     <zero eax>
            clc
          .else
            stc
          .endif
        .endif
        popad
        RestoreReg <es>
        LeaveProc
        ret
EndProc SYIFreeSel


;***LP  Get_Patch_Mem - Get Ram Patch Memory
;
;       Call VMAllocMem and VMLinToPhys to get Ram patches
;
;       ENTRY   (AX:BX) = size of memory needed
;       EXIT    Carry Flag clear on success
;                   (AX:BX) = physical address
;               Carry Flag set on error
;       USES    all registers

Procedure Get_Patch_Mem
assume  ds:NOTHING, es:NOTHING, ss:NOTHING
        LocalVar        _PATCHMEM_SIZE,DWORD
        LocalVar        _PATCH_BASE_PHYS,DWORD
        LocalVar ALLOC_BUFFER,<SIZE vmac_s> ; _VMAlloc buffer

        EnterProc       <ax,bx>
        FlatContext <ds,es>,ax

;       rc = VMAllocMem(cb,cbcommit,fl,hptda,hobowner,hobmte,fselmgr,blkno,pac)

        xor     eax,eax                 ; (EAX) = 0
        mov     ecx,[_PATCHMEM_SIZE]    ; (ECX) = size requested
        xor     edx,edx
        lea     dx,ALLOC_BUFFER         ; (EDX) = flat address of return buffer
        SSToDS  edx
        CCALL32 _VMAllocMem,\
            <ecx, ecx, <RAM_ALLOCF>, eax, ABIOSOWNER, eax, eax, eax, edx>

        .if <zero eax>

          lea     ax,_PATCH_BASE_PHYS   ; Push flat address of return buffer

;       Convert linear to physical
;       rc = VMLinToPhys(laddr,&paddr)

          SSToDS  eax
          CCALL32 _VMLinToPhys,<[ALLOC_BUFFER].ac_va,eax>
          .if <zero eax>
             clc
          .else
             stc
          .endif
        .else
           stc
        .endif
        mov     ax,_PATCH_BASE_PHYSh
        mov     bx,_PATCH_BASE_PHYSl

;       Save off low and high ends of RAM patch area

        .if     <nc>
          DosInitContext <ds>,cx
          mov     ecx,[ALLOC_BUFFER].ac_va
          mov     ABIOSPatchArea_Laddrl,ecx
          add     ecx,[_PATCHMEM_SIZE]
          mov     ABIOSPatchArea_Laddrh,ecx
          mov     ecx,[_PATCH_BASE_PHYS]
          mov     ABIOSPatchArea_Paddrl,ecx
          add     ecx,[_PATCHMEM_SIZE]
          mov     ABIOSPatchArea_Paddrh,ecx
          FlatContext <ds>,cx
          clc
        .endif

        LeaveProc
        ret

EndProc Get_Patch_Mem

;***LP  LoadRAMPatch - Load RAM Patch(s)
;
;       Loads RAM Patches specified in ABIOS.SYS file.
;
;       Runs in Protect Mode using SysInit mini-file system. The following
;       steps are executed:
;       1) Open ABIOS.SYS (SYIOpenFile).
;       2) Allocate memory for contents of ABIOS.SYS (SegAlloc).
;       3) Read in ABIOS.SYS (SYIReadFile).
;       4) Calculate size of RAM Patches (SYIOpenFile).
;       5) Allocate memory for RAM Patch(s) (MemAlloc).
;       6) Read in RAM Patch(s) (SYIReadFile).
;       7) Setup End RAM Patch Sentinel.
;       8) Return Starting Paragraph for RAM Patch(s).
;
;       ENTRY   NONE
;       EXIT    (AX) = Starting Paragraph of RAM Patches (0 if no Patches).
;       EFFECTS RAM Patch(s) loaded (if any).

Procedure LoadRAMPatch
assume  ds:NOTHING, es:NOTHING, ss:NOTHING
        LocalVar        _TMP_SEL,WORD
        LocalVar        _FILESIZE,WORD
        LocalVar        _PATCH_BUFFER,WORD
        LocalVar        _PATCH_BASE_PHYS,DWORD
        LocalVar        _NEXT_PATCH_PHYS,DWORD
        LocalVar        _PATCHMEM_SIZE,DWORD

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

        xor     ax, ax

        mov     _PATCHMEM_SIZEh,  ax
        mov     _PATCHMEM_SIZEl,  ax
        mov     _PATCH_BASE_PHYSh,ax
        mov     _PATCH_BASE_PHYSl,ax


        DosContext      <es>
        lea     di, DOSGROUP:FName
        call    SYIOpenFile

        .if nc and near                 ; File is found
        .if <zero ax> and near
        .if <nonzero bx> near
;
;               Allocate Memory for contents of ABIOS.SYS
;
                xor     ax, ax
                mov     _FILESIZE, bx

                mov     cl, SA_GDT
                mov     ch, D_DATA0

                mov     si, HF_MOVABLE+HF_LOWMEM
                mov     di, ABIOSOWNER

                CALLFAR SegAlloc        ; (bx) = selector (ax) = handle

                .if c
                        InternalError   <ABiosRealInit: SegAlloc Failed>
                .endif

                mov     _TMP_SEL, bx    ; (bx) = selector

;
;               Read in ABIOS.SYS
;
                mov     ax, bx
                xor     bx, bx
                xor     cx, cx
                xor     dx, dx          ; Read whole file

                call    SYIReadFile
                call    SYICloseFile

;
;       Allocate Buffer for Current Patch Headers
;

                xor     ax, ax
                mov     bx, PATCH_BUFFER_SIZE

                mov     cl, SA_GDT
                mov     ch, D_DATA0

                mov     si, HF_MOVABLE+HF_LOWMEM
                mov     di, ABIOSOWNER

                CALLFAR SegAlloc        ; (bx) = selector (ax) = handle

                .if c
                        InternalError   <ABiosRealInit: SegAlloc Failed>
                .endif

                mov     _PATCH_BUFFER, bx ; (bx) = selector
                mov     si, ax          ; (si) = handle


;
;               Determine Size of RAM PATCH AREA
;

                mov     es, _TMP_SEL
                mov     ds, _TMP_SEL
                xor     di, di          ; (es:di) points to filename
                xor     si, si

                .while < si b _FILESIZE > near

                        .while < si b _FILESIZE > and         ; skip blanks
                        .while < <byte ptr [si]> eq LF > or   ;      and EOF
                        .while < <byte ptr [si]> eq CR > or   ; at the beginning
                        .while < <byte ptr [si]> eq EOF > or  ; of abios.sys
                        .while < <byte ptr [si]> eq 0 >
                                lodsb                         ; PTR B719564
                        .endwhile

                        cmp     si, _FILESIZE          ; if null abios.sys
                        je      FreeMemory             ; ignore the patching
                                                       ; and jump away

                        .while < <byte ptr [si]> ne LF > and
                        .while < <byte ptr [si]> ne CR > and
                        .while < <byte ptr [si]> ne EOF >     ;B726641
                                lodsb
                        .endwhile

                        mov     byte ptr [si], 0        ; ASCIIZ

                        call    SYIOpenFile

                        .if c                           ; Missing Patch File
                                SaveReg <ds,es,si>

                                push    ds
                                pop     es              ; (es:di) = name

                                DosInitContext  <ds>
                                mov     si,offset PatchErrMsg
                                mov     [si+size SMT].Offst,di
                                mov     [si+size SMT].Segmt,es
                                call    SYISaveMessage

                                RestoreReg <si,es,ds>
                        .else
;
;       Patch File found. Read the 1st 512 bytes and examine the header.
;       Determine whether or not to apply patch file to patch area.
;

                                SaveReg <ax,bx,es>

                                mov     ax, _PATCH_BUFFER
                                xor     bx, bx

                                xor     cx, cx
                                mov     dx, PATCH_BUFFER_SIZE

                                call    SYIReadFile
                                call    SYICloseFile

                                mov     es, _PATCH_BUFFER
                                assume  es:NOTHING

                                call    CheckRAMPatch

                                RestoreReg      <es,bx,ax>

                                .if c           ; If Patch Necessary
                                        add     _PATCHMEM_SIZEl, bx
                                        adc     _PATCHMEM_SIZEh, ax
                                .else           ; Mark Patch Bad
                                        mov     cx, si
                                        sub     cx, di
                                        xor     al, al
                                        rep     stosb
                                .endif

                        .endif

                        .while < si b _FILESIZE > and
                        .while < <byte ptr [si]> eq LF > or
                        .while < <byte ptr [si]> eq CR > or
                        .while < <byte ptr [si]> eq EOF > or
                        .while < <byte ptr [si]> eq 0 >
                                lodsb
                        .endwhile

                        mov     di, si
                .endwhile

                add     _PATCHMEM_SIZEl, 4      ; space for last patch header
                adc     _PATCHMEM_SIZEh, 0

;
;       Allocate memory for the RAM PATCH AREA
;

                mov     ax, _PATCHMEM_SIZEh     ; (ax:bx) = size
                mov     bx, _PATCHMEM_SIZEl
                call    Get_Patch_Mem
                .if <c>
                  InternalError <AbiosRealInit:Get_PatchMem Failure>
                .endif

;               mov     di, ABIOSOWNER          ; (di) = owner
;               mov     cx, HF_FIXED+HF_LOWMEM  ; (cx) = flags
;               CALLFAR MemAlloc                ; (ax) = handle on exit
;
;               .if c
;                       InternalError   <ABiosRealInit:MemAlloc Failure>
;               .endif
;
;               mov     si, ax          ; (si) = handle
;
;               CALLFAR HandleGetInfo   ; (ax:bx) = physical address on exit
;
                mov     _PATCH_BASE_PHYSh, ax
                mov     _PATCH_BASE_PHYSl, bx
                DosInitContext  es
                mov     di,offset gdtsel
                mov     cx,1
                CALLFAR AllocateGDTSelector
                assume  es:nothing
;
;       Read in RAM PATCHES
;

                mov     _NEXT_PATCH_PHYSh, ax
                mov     _NEXT_PATCH_PHYSl, bx

                mov     ds, _TMP_SEL
                mov     es, _TMP_SEL
                xor     di, di          ; (es:di) points to filename
                xor     si, si

                .while < si b _FILESIZE > near

                        .if <<byte ptr [si]> ne 0>  near

                                call    SYIOpenFile

                                .if nc  near
                                        mov     _PATCHMEM_SIZEl, bx
                                        mov     _PATCHMEM_SIZEh, ax
                                        SaveReg <ds,cx,dx,si,es>
                                        DosInitContext  ds
                                        .while  <_PATCHMEM_SIZEh ge 1>
                                                xor     cx,cx
                                                mov     bx, _NEXT_PATCH_PHYSl
                                                mov     ax, _NEXT_PATCH_PHYSh
                                                mov     si, gdtsel
                                                CALLFAR PhysToGDTSelector    ;gdtsel -> 64kb buffer
                                                mov     ax,si
                                                xor     bx,bx
                                                mov     cx,1
                                                xor     dx,dx
                                                call    SYIReadFile
                                                inc     _NEXT_PATCH_PHYSh
                                                dec     _PATCHMEM_SIZEh
                                        .endwhile
                                        mov     cx,_PATCHMEM_SIZEl      ;set size = sizel
                                        .if     <cx ne 0>       .then
                                                mov     bx, _NEXT_PATCH_PHYSl
                                                mov     ax, _NEXT_PATCH_PHYSh
                                                mov     si, gdtsel
                                                CALLFAR PhysToGDTSelector    ;gdtsel -> buffer
                                                mov     ax,si
                                                xor     bx,bx

                                                xor     cx, cx
                                                mov     dx, _PATCHMEM_SIZEl

                                               call  SYIReadFile

                                               mov     ax,_NEXT_PATCH_PHYSh
                                               mov     bx,_NEXT_PATCH_PHYSl
                                               add     bx,_PATCHMEM_SIZEl
                                               adc     ax,0

                                               mov     _NEXT_PATCH_PHYSl, bx
                                               mov     _NEXT_PATCH_PHYSh, ax
                                        .endif
                                        call    SYICloseFile
                                        RestoreReg      <es,si,dx,cx,ds>
                                        assume  ds:nothing
                                .endif

                                .while < <byte ptr [si]> ne 0 >
                                        lodsb
                                .endwhile
                        .endif

                        .while < si b _FILESIZE > and
                        .while < <byte ptr [si]> eq LF > or
                        .while < <byte ptr [si]> eq CR > or
                        .while < <byte ptr [si]> eq EOF > or
                        .while < <byte ptr [si]> eq 0 >
                                lodsb
                        .endwhile

                        mov     di, si
                .endwhile
                SaveReg <ds>
                DosInitContext  ds
                mov     ax,gdtsel
                CALLFAR FreeGDTSelector
                RestoreReg      <ds>
                assume  ds:nothing

;
;               Setup end of RAM PATCH AREA header
;

                mov     ax, _NEXT_PATCH_PHYSh
                mov     bx, _NEXT_PATCH_PHYSl

                NullContext es

                call    RealModeIC

                mov     si,bx           ; calc offset part of virt address
                and     si,0fh          ; this is low four bits of phys addr

                and     bl,0f0h         ; calculate paragraph part
                or      ax,bx
                ror     ax,4
                mov     ds,ax           ; ds:si = end of RAM Patch Area

                mov     [si].RamPatchSig, 0aa55h
                mov     [si].RamPatchSize, 0

                call    ProtModeIC

;
;       Free ABIOS.SYS Memory and 512 byte patch buffer
;

FreeMemory:
                mov     ax, _TMP_SEL
                CALLFAR SegFree

                mov     ax, _PATCH_BUFFER
                CALLFAR SegFree
;
;       Setup return of RAM PATCH PARAGRAPH
;

                mov     ax, _PATCH_BASE_PHYSh
                mov     bx, _PATCH_BASE_PHYSl
                or      ax, bx
                ror     ax, 4                   ; (ax) = _PATCH_PARA

        .else
;
;       ABIOS.SYS is missing
;
                                            ; (es:di) = file name from OpenFile
                DosInitContext  <ds>
                mov     si,offset PatchErrMsg
                mov     [si+size SMT].Offst,di
                mov     [si+size SMT].Segmt,es
                call    SYIAbort
        .endif
        RestoreReg      <es,ds,di,si,dx,cx,bx>
        LeaveProc
        ret
EndProc LoadRAMPatch


;***LP  CheckRAMPatch - Check RAM Patch Level
;
;       Compare Model, Sub-Model, and Revision in Patch Header to that of the
;       machine.
;
;       1) Check For Valid RAM Patch Signature
;       2) Get Machine's Model, Sub-Model, and Revision
;       3) Compare Machine Specific Level to Ram Patch Level
;       4) If patch is for all systems (wild card) or for this particular
;          system, load it.
;       5) If wild card patch and extended header, call ABIOS to determine if
;          the patch should be loaded.  Returns AX = size of patch to be loaded.
;          (Allows patch to resize itself)  Must call ABIOS in RMODE so ABIOS
;          can query BIOS.
;
;          OEMs have used the same model byte, submodel byte, BIOS rev level
;          as on IBM systems which causes confusion when IBM ABIOS patch files
;          are trying to determine whether to install.  So, it is necessary
;          for this code to check for IBM systems and IBM patch files before
;          calling the wildcard routine to initialize.  Otherwise IBM ABIOS
;          patch files with wildcard routines may request installation on
;          OEM systems with IBM model byte, submodel byte, BIOS rev levels.
;
;          Listed below is the decison table used to decide on what systems
;          system initialization should load what ABIOS patch files.  It is
;          obvious sysinit wants to load IBM patch files on IBM systems and
;          OEM patch files on OEM systems.  Not so obvious is that Core Int.
;          and Procom have patch files which must load on IBM systems or that
;          IBM ABIOS patch files (SCSI) sometimes must load on OEM systems.
;          The enhanced wildcard ABIOS patch file entry point must determine
;          what system they are running on and whether their adapter is
;          present before telling us whether the patch file should be loaded.
;
;          +--------+-------+----------+----------+---------+
;          | IBM    | IBM   | WILDCARD | SPECIFIC | INSTALL |
;          | SYSTEM | PATCH | PATCH    | PATCH    | PATCH?  |
;          +--------+-------+----------+----------+---------+
;          |   Y    |   Y   |    Y     |    N     |   Y     |
;          |   Y    |   Y   |    N     |    Y     |   Y     |
;          |   Y    |   N   |    Y     |    N     |   Y     |
;          |   Y    |   N   |    N     |    Y     |   Y     |
;          |   N    |   Y   |    Y     |    N     |   N     |
;          |   N    |   Y   |    N     |    Y     |   N     |
;          |   N    |   N   |    Y     |    N     |   Y     |
;          |   N    |   N   |    N     |    Y     |   Y     |
;          +--------+-------+----------+----------+---------+
;
;       ENTRY   (ES:0) -> RAM Patch Header
;
;       EXIT    Carry Flag *clear* if RAM Patch Not Correct Level
;               Carry Flag *set* if RAM Patch OK For Loading

Procedure CheckRAMPatch
assume  ds:NOTHING, es:NOTHING, ss:NOTHING

        LocalVar fIBMPatch,WORD
        LocalVar MODSUB,WORD
        LocalVar BIOREV,WORD
        EnterProc

        pusha
        push    ds
        push    es
        DosContext      <ds>

        call    ABIOSPatchOwner                         ; IBM or OEM patch?
        .if     nz
          mov   fIBMPatch,0                             ; OEM patch
        .else
          mov   fIBMPatch,1                             ; IBM patch
        .endif

        mov     al, DevConfigTbl.Config_model
        mov     ah, DevConfigTbl.Config_type
        mov     bl, ABIOS_Revision

        mov     MODSUB,ax
        mov     BIOREV,bx

        .if <es:[0].RamPatchSig eq 0aa55h> and near     ; Patch all systems?
        .if <es:[0].RamPatchModel eq 0> and near
        .if <es:[0].RamPatchSubModel eq 0> and near
        .if <es:[0].RamPatchRevision eq 0> near
                .if <es:[0].RamPatchExtLength ne 0> and ; Extended Header?
                .if <es:[0].RamPatchWildCard ne 0>      ; Wild card entry point?
                        mov     ax,es:[0].RamPatchWildCard
                        mov     word ptr wildcardroutine,ax ; Save offset

                        mov     bx,es                   ; input:  BX = Selector
                        CALLFAR SelToSeg                ; (ax) = para on exit
                        .if     <nc>
                                mov     word ptr wildcardroutine+2,ax
                                call    RealModeIC
                                mov     ax,MODSUB       ; input:  AX = model/sub
                                mov     bx,BIOREV       ; input:  BX = bio rev
                                call    dword ptr [wildcardroutine]
                                call    ProtModeIC
                                .if <ax eq 0>           ; Patch size (bytes)
                                        clc             ; No, don't load patch
                                .else
                                        stc             ; Yes, load patch
                                .endif
                        .endif
                .else
                        .if <fIBMSystem eq CFG_IBM_ABIOS>; If IBM system D90588
                             stc                        ; Yes, load patch
                        .else
                             .if <fIBMSystem eq CFG_OEM_ABIOS> and  ; If OEM system and ;D91506
                             .if <fIBMPatch eq 0>       ; If OEM patch
                                 stc                    ; Yes, load patch
                             .else
                                 clc                    ; No, don't load patch
                             .endif
                        .endif
                .endif
        .else
                .if <es:[0].RamPatchSig eq 0aa55h> and ; Patch this system only?
                .if <es:[0].RamPatchModel eq al> and
                .if <es:[0].RamPatchSubModel eq ah> and
                .if <es:[0].RamPatchRevision eq bl>
                        .if <fIBMSystem eq CFG_IBM_ABIOS>; If IBM system D90588
                             stc                        ; Yes, load patch
                        .else
                             .if <fIBMSystem eq CFG_OEM_ABIOS> and  ; If OEM system and ;D91506
                             .if <fIBMPatch eq 0>       ; If OEM patch
                                 stc                    ; Yes, load patch
                             .else
                                 clc                    ; No, don't load patch
                             .endif
                        .endif
                .else
                        clc                             ; No, don't load patch
                .endif
        .endif

        pop     es
        pop     ds
        popa
        LeaveProc
        ret
EndProc CheckRAMPatch


;***LP  SystemOwner - Check if IBM or OEM System Unit
;
;       Compare copyright notice to determine if IBM or OEM system unit.
;
;       ENTRY
;
;       EXIT    JZ  - IBM system unit
;               JNZ - OEM system unit

Procedure SystemOwner
assume  ds:NOTHING, es:NOTHING, ss:NOTHING

        push    es
        push    ds
        pusha

        mov     ax,0f000h                               ; segment
        mov     ebx,CODE_ALLOCF                         ; alloc flags
        mov     ecx,0ffffh                              ; length
        mov     edx,CODE_SEL_ALLOCF                     ; selector flags
        call    GetSelector

        mov     es,di                                   ; es = selector
        mov     di,0E000h                               ; di = offset

        ; look for system copyright statement passed system part number.
        mov     cx,22                                   ; loop counter
sysown0:
        cmp     byte ptr es:[di],'C'                    ; start of copyright?
        je      sysown1                                 ; yes
        inc     di                                      ; point to next char
        loop    sysown0                                 ; look for copyright

sysown1:
        mov     cx,syscopyright1len                     ; get copyright len
        DosInitContext <ds>
        mov     si,OFFSET systemcopyright1              ; ds:si -> system string
        call    strncmp                                 ; IBM or OEM patch?
        je      sysown2                                 ; IBM, exit

        mov     cx,syscopyright2len                     ; get copyright len
        mov     si,OFFSET systemcopyright2              ; ds:si -> system string
        call    strncmp                                 ; IBM or OEM patch?
        je      sysown2                                 ; IBM, exit

        mov     cx,syscopyright3len                     ; get copyright len
        mov     si,OFFSET systemcopyright3              ; ds:si -> system string
        call    strncmp                                 ; IBM or OEM patch?
        je      sysown2                                 ; IBM, exit

sysown2:
        popa
        pop     ds
        pop     es
        ret
EndProc SystemOwner


;***LP  ABIOSPatchOwner - Check if IBM or OEM ABIOS Patch File
;
;       Compare copyright notice to determine if ABIOS patch file is an
;       IBM or OEM patch file.
;
;       ENTRY   (ES:0) -> RAM Patch Header
;
;       EXIT    JZ  - IBM ABIOS Patch File
;               JNZ - OEM ABIOS Patch File

Procedure ABIOSPatchOwner
assume  ds:NOTHING, es:NOTHING, ss:NOTHING

        push    ds
        mov     di,RamPatchSTDLen                       ; standard header length
        cmp     es:[0].RamPatchExtLength,0              ; extended header?
        je      apo1                                    ; no
        add     di,es:[0].RamPatchExtLength             ; yes, add ext hdr len
apo1:
        mov     cx,rpcopyrightlen                       ; get copyright len
        DosInitContext <ds>
        mov     si,OFFSET rampatchcopyright             ; ds:si -> patch string
        call    strncmp                                 ; IBM or OEM patch?
        pop     ds
        ret
EndProc ABIOSPatchOwner


;***LP  strncmp - String Compare routine
;
;       Compare 2 strings of length n and return whether they are equal.
;
;       ENTRY   DS:SI -> STRING 1
;               ES:DI -> STRING 2
;               CX    =  length used in comparison
;
;       EXIT    JZ  = Strings are identical
;               JNZ = Strings are not identical

Procedure strncmp
assume  ds:NOTHING, es:NOTHING, ss:NOTHING

        push    si
        push    di
        push    cx
        cld
  repe  cmpsb
        pop     cx
        pop     di
        pop     si
        ret
EndProc strncmp


;***LP  syiABiosProtInit - - ABIOS Protect Mode Initialization
;
;       Build the Protect Mode Common Data Area.
;
;       Builds the Protect Mode Common Data Area in a hi-memory segment. This
;       routine executes in PROTECT MODE ONLY. The following steps are
;       executed:
;
;       1) Allocate a GDT selector (GDTAlloc) and fill it with information
;          from GDT register (SetDescInfo).
;       2) Allocate memory for Protect Mode ABIOS Segment (SegAlloc).
;       3) Allocate Memory for Selector Allocation Table (SegAlloc).
;       4) Copy the Real Mode CDA+FTTs to Protect Mode ABIOS Segment
;          (DOSGROUP:ProtSegSize).
;       5) Map the planar ROMs into the GDT (GetSelector).
;       6) Edit FTT and DB pointers in Protect Mode CDA and
;          edit the Protect Mode Function Transfer Tables.
;       7) Convert the physical Data Pointer Addresses to Segment:Offset
;          format in the Real Mode CDA and then map the Segment values in
;          the GDT and stuff the selectors in the Segment fields of the
;          Protect Mode Data Pointers.
;       8) Free the memory for the Selector Allocation Table
;       9) Free the GDT selector (GDTFree) which contained information
;          from GDT register.
;
;       ENTRY   [DOSGROUP:RealCDASel] - Selector for Real Mode ABIOS Segment
;               [DOSGROUP:ProtSegSize] - Size to alloc for ProtMode ABIOS Seg
;
;       EXIT    NONE
;       EFFECTS Protect Mode CDA constructed.

Procedure syiABiosProtInit
assume ds:nothing,es:nothing,ss:nothing

        LocalVar SaveTableSel,WORD      ;selector for table of fixed-up offsets
        LocalVar vmac,<SIZE VMAC>       ; ** dcr 660
        LocalVar GDTReg,FWORD

        EnterProc
        pusha
        SaveReg         <ds,es>

;       Allocate a GDT selector and fill it with information from GDT
;       register.

        CALLFAR GDTAlloc
        .if     <nc>
          DosInitContext <ds>
          mov     ABIOSPatchArea_GDTReg,ax
          push    ax
          push    ax
          mov     al,D_DATA0
          mov     ah,SD_ALL
          push    ax
          sgdt    GDTReg
          mov     ax,[GDTReg].GDTRegLaddrh
          push    ax
          mov     ax,[GDTReg].GDTRegLaddrl
          push    ax
          xor     ax,ax
          push    ax
          mov     ax,[GDTReg].GDTRegLimit
          inc     ax
          push    ax
          CALLFAR SetDescInfo
          .if     <c>
            InternalError   <syiABiosProtInit:SetDescInfo failed>
          .endif
        .else
          InternalError   <syiABiosProtInit:GDTAlloc failed>
        .endif

;
;       Allocate memory for Protect Mode ABIOS Segment
;
        DosContext      <ds>
        movzx   ecx,[ProtSegSize]       ; ecx = Size of segment

        FlatContext <ds,es>,eax         ; set up for C calls
        SSToDS  eax,vmac

;       Allocate the memory segment:
;       rc = SELAllocKHB(hkh, cb, fl, flselmgr, hobowner, pac)

        CCALL32 _SELAllocKHB,<VM_HKH_PUB_RESRW, \
                              ecx, \
                              <PG_RESIDENT+PG_U+PG_CONTIG>, \
                              <D_DATA+D_DPL0>, \
                              ABIOSOWNER, \
                              eax>
        or      eax,eax
        .if     nz                     ; did the SELAlloc fail?
           InternalError <ABIOSProtInit: SELAllocKHB failed> ; yes, halt the system
        .endif

        mov     bx,vmac.ac_sel          ; BX = SEL

        DosContext      <ds>
        mov     ABIOS_CDA_anchor_p, bx  ; Initialize Protect Mode Anchor

;
;       Copy the Real Mode CDA and FTTs to Protect Mode CDA Segment
;

        mov     cx, ProtSegSize                 ; Size to move (bytes)
        shr     cx, 1                           ; Size to move (words)
        mov     es, bx                          ; Protect Only Segment
        mov     ds, RealCDASel                  ; Real Mode Segment Selector

        xor     di, di                          ; Start of segment(s)
        xor     si, si

        rep     movsw                           ; Move It !!!

;
;       Map the Planar ROMs into the GDT
;       Ring 0 Code Segments, Limit = 64K
;

        mov     ax, 0e000h
        mov     ecx, 0ffffh
;       mov     dh, D_CODE0
        mov     ebx,CODE_ALLOCF
        mov     edx,CODE_SEL_ALLOCF
        call    GetSelector

        mov     ax, 0f000h
        mov     ebx,CODE_ALLOCF
        mov     edx,CODE_SEL_ALLOCF
        call    GetSelector
        SaveReg <ds>

;####
;####   Allocate memory for saving fixed-up offsets
;####

        DosContext      <ds>
        mov     ax, es:[0].CDALids      ;# of lids to determine max # of possible fix-ups
        mov     bx, 2
        mul     bx
        xor     ecx,ecx                 ;** dcr 660
        mov     cx, ax

        SaveReg <es,si,di>

;       Allocate the memory segment

        FlatContext <ds,es>,eax         ; set up for C calls
        SSToDS  eax,vmac

;       rc = SELAllocKHB(hkh, cb, fl, flselmgr, hobowner, pac)

        CCALL32 _SELAllocKHB,<VM_HKH_PUB_RESRW, \
                              ecx, \
                              <PG_RESIDENT+PG_U+PG_CONTIG>, \
                              <D_DATA+D_DPL0>, \
                              ABIOSOWNER, \
                              eax>
        or      eax,eax
        .if     nz                     ; did the SELAlloc fail?
           InternalError   <ABiosProtInit: SELAlloc Failed for SaveTable>
        .endif

        mov     bx,vmac.ac_sel          ; BX = SEL
        RestoreReg <di,si,es,ds>
        mov     SaveTableSel, bx        ; Initialize SaveTableSel

;
;       Edit FTT and DB pointers
;
;       ES = Protect CDA Segment Selector
;       DS = Real Mode CDA Segment Selector
;       DI = counter for ftts that have been mapped

        mov     cx, es:[0].CDALids
        sub     cx, 2
        mov     dx, 2
        xor     di, di

        mov     ax, 0                           ;### init # of fixes
                                                ;### selectable boot
        .repeat
                mov     bx, dx
                shl     bx, 3

                .if < es:[bx].FTTSegment ne 0 >
                        mov     es:[bx].FTTSegment, es
;#####################################################################
;### Selectable boot fix                                             #
;### Create and search a table of all selectors that have been fixed #
;### The old method assumed adjacency among like devices in CDA      #
;#####################################################################
;
                        SaveReg  <dx,ax,ds,es>
                        DosInitContext  <ds>
                        mov     es,SaveTableSel          ;### Get table addr
                        xor     di, di
                        mov     dx,0
                        .while <ax ne 0>
                            mov         dx,es:[di]        ;### Compare current offset
                            RestoreReg  <es>              ;###
                            .if <dx eq es:[bx].FTTOffset> ;### with table of fixed offsets
                                 mov    ax, 1             ;### If found terminate loop
                                 mov    dx, 1             ;### set dx so selector will not be fixed
                            .else
                                 mov    dx, 0
                            .endif
                            SaveReg     <es>
                            mov     es,SaveTableSel          ;### Get table addr
                            add     di, 2                    ;### Get next table entry
                            dec     ax
                         .endwhile
                         .if <dx eq 0>                       ;### Offset to be fixed
                                RestoreReg      <es,ds,ax>
                                mov     si, es:[bx].FTTOffset
                                call    EditFTT
                                inc     ax
                                mov     dx, es:[bx].FTTOffset ;### Save fixed offset
                                SaveReg <ax,ds,es>
                                DosInitContext  <ds>
                                mov     es,SaveTableSel       ;### Get table addr
                                mov     es:[di], dx           ;### in table
                         .endif
                         RestoreReg      <es,ds,ax,dx>
                .endif
                .if < es:[bx].DBSegment ne 0 >
                        mov     es:[bx].DBSegment, ds
                .endif
                inc     dx
                dec     cx
        .until  <cxz>   near

;### Free SaveTableSel selector
        SaveReg <es,ds>                         ;** dcr 660
        FlatContext <ds,es>,eax

;       SELFreeKHB(hkh, fl, sel)

        movzx   eax,[SaveTableSel]
        CCALL32 _SELFreeKHB,<VM_HKH_PUB_RESRW,NA,eax>

        RestoreReg <ds,es>
;
;       Convert the Data Pointers from 32 Bit Physical Address to Seg:Off
;
;       ES = ProtMode CDA
;       DS = Real Mode CDA
;

        mov     si, es:[0].CDADPOffset          ; Point at last Data Pointer
        mov     cx, es:[si+6]                   ; Initialize Count

        .repeat

                SaveReg <cx>

                mov     ax, [si].PhysMSW
                mov     bx, [si].PhysLSW

                mov     dx, bx
                and     dx, 000Fh

                and     bx, not 000Fh
                or      bx, ax
                ror     bx, 4

;       Setup Real CDA Data Pointers

                .if < ax ae 0010h >             ; If Above 1M
                        mov     [si].DOffset, 0
                        mov     [si].DSegment, 0
                .else
                        mov     [si].DOffset, dx
                        mov     [si].DSegment, bx
                .endif

;
;       Setup Protect CDA Data Pointers and Map them in the GDT
;


                xor     ecx,ecx
                mov     cx, es:[si].DLimit      ; CX = Limit
                test    bx,0ffh
                .if     <nz>
                        mov     ax,bx
                        and     ax,0ffh
                        rol     ax,4
                        add     dx,ax
                        add     cx,ax
                        and     bx,not 0ffh
                .endif


                mov     es:[si].DOffset, dx
                mov     es:[si].DLimit,cx

                mov     ax, bx                  ; AX = Segment
;               mov     dh, D_DATA0             ; DH = Access
                mov     ebx,DATA_ALLOCF
                mov     edx,DATA_SEL_ALLOCF

                call    GetSelector             ; DI = selector

                mov     es:[si].DSegment, di    ; Stuff Data Pointer Selector

                sub     si, size DataPtr        ; Next Data Pointer

                RestoreReg      <cx>
        .loop

;       Free the GDT selector which contained information from GDT register.

        DosInitContext <ds>
        mov     ax,ABIOSPatchArea_GDTReg
        CALLFAR GDTFree

        RestoreReg      <es,ds>
        popa
        LeaveProc
        ret

EndProc syiABiosProtInit


;***LP  GetSelector - Create a Selector mapping
;
;       Gets a selector that maps the segment specified into the GDT.
;
;       Maintains a list of selectors allocated, thus preventing multiple
;       entries in the GDT to the same segment. If the specified segment
;       is already mapped in the GDT (ie Selector Table), then the
;       mapped selector is returned. Otherwise a new Selector Table entry
;       is allocated and the newly mapped selector is returned.
;
;       ENTRY   (EAX) = segment (paragraph address)
;               (EBX) = allocation flags
;               (ECX) = limit
;               (EDX) = selector flags
;       EXIT    (DI) = Selector mapping corresponding segment
;       USES    DI, Flags

Procedure GetSelector
assume  ds:NOTHING, es:NOTHING, ss:NOTHING
        SaveReg         <ax,ebx,cx,dx,si,ds>
        DosInitContext  <ds>
        lea     di, DOSINITDATA:ABIOSSelTable   ; (ds:di) = SelTable

        .while <[di].SelTblSel ne 0>

                .if <[di].SelTblSeg eq ax> and
                .if <[di].SelTblLimit eq cx> and
                .if <[di].SelTblAccess eq ebx>
                        mov     di, [di].SelTblSel
                        jmp     gsexit
                .endif

                add     di, size SelTblEntry

        .endwhile

        .if <di b <offset DOSINITDATA:ABIOSSelTableEnd>>

                SaveReg <di,ebx>                    ; Save offset for new entry

                call    SYIAllocSel

                RestoreReg      <ebx,si>            ; ES:SI = new SelTbl entry

                mov     [si].SelTblSel, di
                mov     [si].SelTblSeg, ax
                mov     [si].SelTblLimit, cx
                mov     [si].SelTblAccess, ebx

        .else
                InternalError   <GetSelector: ABIOSSelTable Full>
        .endif

gsexit:
        RestoreReg      <ds,si,dx,cx,ebx,ax>
        ret
EndProc GetSelector


;***LP  EditFTT - Edit Function Transfer Table
;
;       Set up a Function Transfer Table for Protect Mode.
;
;       Maps the segment values of the ABIOS entry points into the GDT for
;       Protect Mode Operation.
;
;       ENTRY   (ES:SI) -> FTT to edit
;       EXIT    NONE
;       EFFECTS Function Transfer Table edited for Protect Mode Operation

Procedure EditFTT
        SaveReg         <cx,si>

        add     si, 2                           ; Index to Segment Field

        mov     cx, 3
        .repeat                                 ; Edit FTT Entry(s)
                call    EditFTTEntry
                add     si, 4   ; Next Entry
        .loop

        sub     si, 2           ; Address Count Field

        .if < <word ptr es:[si] > ne 0h >       ; If More ENtry Points

                mov     cx, es:[si]             ; Setup Count
                add     si, 6                   ; Address 1st Seg Entry

                .repeat                         ; Edit FTT Entry(s)
                        call    EditFTTEntry
                        add     si, 4   ; Next Entry
                .loop
        .endif

        RestoreReg      <si,cx>
        ret
EndProc EditFTT


;***LP  EditFTTEntry - Edit Function Transfer Table Entry
;
;       Set up a Function Transfer Table Entry for Protect Mode.
;
;       Maps the segment values of the ABIOS entry point into the GDT for
;       Protect Mode Operation.  Sets up a temporary selector to see if the
;       entry refers to a RAM Patch for Limit setting on the descriptor finally
;       created.  Otherwise limit is fffe (see 286 errata).
;
;       ENTRY   (ES:SI) -> FTT Entry to edit
;
;       EFFECTS Function Transfer Table Entry edited for Protect Mode Operation

Procedure EditFTTEntry
        SaveReg <ax,ebx,ecx,edx,di,ds>

        .if < <word ptr es:[si]> ne 0>

                mov     ax, es:[si]     ; (ax) = Segment
                mov     ecx, 0ffffh      ; (cx) = Limit
;               mov     dh, D_CODE0     ; (dh) = Access
                mov     ebx,DATA_ALLOCF
                mov     edx,DATA_SEL_ALLOCF
                call    SYIAllocSel



;
;       Check if FTT Entry is from RAM Patch. If yes, examine Patch
;       Header and reset the Limit in the Descriptor.
;

                mov     ds, di
                assume  ds:NOTHING
                .if <ds:[0].RamPatchSig eq 0aa55h>      ; if RAM Patch
                                                        ; Calculate Limit
                        xor     ecx,ecx
                        mov     cl, ds:[0].RamPatchSize ; Get size of patch
                        shl     cx, 9                   ; x 512
                        dec     cx                      ; Size to Limit
                .endif
                call    SYIFreeSel              ;ebx linear address

                mov     ebx,CODE_ALLOCF
                mov     edx,CODE_SEL_ALLOCF
                call    GetSelector     ; (di) = selector
                mov     es:[si], di     ; Stuff Code Selector

        .endif

        RestoreReg      <ds,di,edx,ecx,ebx,ax>
        ret
EndProc EditFTTEntry


INITCODE ends

        end
