/*
 * IBM Confidential
 *
 * Copyright (c) IBM Corporation 1993
 *
 * All Rights Reserved
 */

/*
 * os2mem.c - routines to lie about physical memory in the machine.
 */

#include <os2def16.h>
#include <sysinvar.h>
typedef unsigned long DWORD;
typedef unsigned short WORD;
#include <dos.h>
#include <dbprt.h>
#include <osconst.h>
#include <ostypes.h>
#include <ordinals.h>
#include <pgexport.h>
#include <vmowner.h>
#include <filetab.h>
#include <mi.h>
#include <eisa.h>
#include <doshlp.h>
#include "loader.h"

extern void dprintf(char *,...);
extern unsigned long FatReadInit(unsigned long);

extern struct filetable_s filetable;

extern unsigned LowMem;
extern unsigned HighMem;
extern unsigned long ExtendMem;
extern unsigned Int1588Mem;             // amount of protect mem 1MB to 64MB-1
extern unsigned Int15E8Mem;             // 69458  amount 16M to 64M on
extern struct Int15c7Table Int15c7Mem;
extern unsigned char AoxMem[17];        // info on memory on Aox MicroMaster

extern unsigned char BootFlag;
extern void BootErrFSD(void);
extern void BootErrOS2MEM(void);
extern void BootMsgOS2MEM(void);
extern unsigned long ldrframe;


extern unsigned char OS2MEMname[];
#define ABSOLUTE 1
#define RELATIVE 0
#define STRICT   1
#define NOSTRICT 0

/*** fakemem -lie about physical memory in the machine.
 *
 *  INPUT:
 *          ldrseg      -   Segment of the loader image
 *          ldrlen      -   Length of the loader image
 *
 *  NOTE:
 *          This function is called during the boot process to
 *          lie about physical memory in the machine.
 */

void fakemem (  unsigned short ldrseg,
                unsigned short ldrlen)
{
    DWORD     i;
    DWORD     cbOS2MEM;              /* # bytes in filee */
    char far *fpmemfilebuffer;       /* pointer to Message file buffer */
    char      AbsOrRel=ABSOLUTE;
    char      Strict=NOSTRICT;
    DWORD     FakeMemSize=0;
    DWORD     RealMemSize=0;
    DWORD     FakeMemDelta=0;

    if (BootFlag)
        {
        // Non-FAT boot system.
        // Verify that we are able to load the OS2LDR.MSG file.
        if (!(BootFlag & BF_MICROFSD))
            {
            BootErrFSD();
            }

        }
    else
        {
        // If on a FAT boot system, initialize the FAT.
        FatReadInit( ldrframe << PAGESHIFT );
        }


    DBPRT(17,("opening OS2MEM\n"));

    // Open OS2MEM file
    if ( filetable.ft_muOpen( (char far *) OS2MEMname,
                              (unsigned long far *) &cbOS2MEM) )
        {
        DBPRT(17,("no OS2MEM\n"));
        return;
        }

    DBPRT(17,("OS2MEM %u bytes\n",cbOS2MEM));

    if (cbOS2MEM >= 25) //OS2MEM  not a reasonable size?
        {
        DBPRT(17,("OS2MEM too big, size=%lu\n",cbOS2MEM));
        return;
        }

    fpmemfilebuffer = ftofar(segtof(ldrseg) + BYTESTOPAGE(ldrlen));

    // Read entire file in for parsing
    filetable.ft_muRead( 0L,fpmemfilebuffer, (long) SECTROUND(cbOS2MEM));
    DBPRT(17,("OS2MEM read\n"));

    /////////////////////////////////////////////////////////////////////////
    // Start Parse OS2MEM file
    /////////////////////////////////////////////////////////////////////////

    i=0;
    if ((fpmemfilebuffer[i] == 'a') ||
        (fpmemfilebuffer[i] == 'A'))
       {
       AbsOrRel = ABSOLUTE;
       i++;
       }
    else if ((fpmemfilebuffer[i] == 'r') ||
             (fpmemfilebuffer[i] == 'R'))
       {
       AbsOrRel = RELATIVE;
       i++;
       }

    //Skip blanks
    while(fpmemfilebuffer[i] == ' ')
       {
       i++;
       }


    if ((fpmemfilebuffer[i] == 's') ||
        (fpmemfilebuffer[i] == 'S'))
       {
       Strict = STRICT;
       i++;
       }


    //Skip blanks
    while(fpmemfilebuffer[i] == ' ')
       {
       i++;
       }


    //Get Fake memory size
    while((fpmemfilebuffer[i] >= '0') &&
          (fpmemfilebuffer[i] <= '9'))
       {
       FakeMemSize = (FakeMemSize*10)+(fpmemfilebuffer[i]-'0');
       i++;
       }


    /////////////////////////////////////////////////////////////////////////
    // End Parse OS2MEM file
    /////////////////////////////////////////////////////////////////////////

    RealMemSize = LowMem + HighMem+ ExtendMem;

    if (AbsOrRel == RELATIVE)
       {
       DBPRT(17,("R -%08lx\n",(((RealMemSize+1024-1) & ~(1024-1)) - RealMemSize)));
       FakeMemSize = FakeMemSize -
                     (((RealMemSize+1024-1) & ~(1024-1)) - RealMemSize);
       DBPRT(17,("OS2MEM R\n"));
       }
    else
       {
       DBPRT(17,("A -%04x\n",(((LowMem+64-1) & ~(64-1)) - LowMem)));
       FakeMemSize = FakeMemSize -
                     (((LowMem+64-1) & ~(64-1)) - LowMem);
       DBPRT(17,("OS2MEM R\n"));
       }

    DBPRT(17,("RealMem =%08lx\n",RealMemSize));
    DBPRT(17,("FakeMem =%08lx\n",FakeMemSize));

    // Check to make sure we really have as much memory as OS2MEM says
    // And user is asking for at least 3.5
    if ((FakeMemSize > RealMemSize) ||
        (FakeMemSize <= 3584))
       {
       if (Strict == STRICT)
          {
          BootMsgOS2MEM();
          BootErrOS2MEM();
          }
       else
          {
          BootMsgOS2MEM();
          return;
          }
       }

    FakeMemDelta = RealMemSize - FakeMemSize;

    ///////////////////////////////////////////////////////////////////////
    //Find Fake Memory size (in 1K blocks) above 1MB
    //And fake out the >1MB (in 1K blocks) values

    FakeMemSize -= LowMem;

    if ((DWORD)Int1588Mem > FakeMemSize)
       {
       Int1588Mem -= FakeMemDelta;
       }
    if (Int15c7Mem.LocHiMem > FakeMemSize)
       {
       Int15c7Mem.LocHiMem -= FakeMemDelta;
       }
    if (Int15c7Mem.SysHiMem  > FakeMemSize)
       {
       Int15c7Mem.SysHiMem  -= FakeMemDelta;
       }
    if (Int15c7Mem.CacHiMem > FakeMemSize)
       {
       Int15c7Mem.CacHiMem -= FakeMemDelta;
       }

    ///////////////////////////////////////////////////////////////////////
    //Find Fake Memory size (in 1K blocks) above 16MB
    //And fake out the >16MB (in 1K blocks) values

    if ((FakeMemSize+1024) > (16*1024))
       {
       FakeMemSize -= (15*1024);

       if (Int15c7Mem.LocExMem > FakeMemSize)
          {
          Int15c7Mem.LocExMem -= FakeMemDelta;
          }
       if (Int15c7Mem.SysExMem > FakeMemSize)
          {
          Int15c7Mem.SysExMem -= FakeMemDelta;
          }
       if (Int15c7Mem.CacExMem > FakeMemSize)
          {
          Int15c7Mem.CacExMem -= FakeMemDelta;
          }
       ///////////////////////////////////////////////////////////////////////
       //Find Fake Memory size (in 64K blocks) above 16MB
       //And fake out the >16MB (in 64K blocks) values

       FakeMemSize  = FakeMemSize/64;
       FakeMemDelta = FakeMemDelta/64;
       if ((DWORD)Int15E8Mem > FakeMemSize)
          {
          Int15E8Mem -= FakeMemDelta;
          }
       }

    filetable.ft_muClose();
    return;

}

