mirror of https://github.com/FDOS/kernel.git
New file by Tom Ehlert for HMA initialization.
git-svn-id: https://svn.code.sf.net/p/freedos/svn/kernel/trunk@168 6ac86273-5f31-0410-b378-82cca8765d1b
This commit is contained in:
parent
f2184025da
commit
8dff303fda
|
@ -0,0 +1,534 @@
|
|||
/****************************************************************/
|
||||
/* */
|
||||
/* initHMA.c */
|
||||
/* DOS-C */
|
||||
/* */
|
||||
/* move kernel to HMA area */
|
||||
/* */
|
||||
/* Copyright (c) 2001 */
|
||||
/* tom ehlert */
|
||||
/* All Rights Reserved */
|
||||
/* */
|
||||
/* This file is part of DOS-C. */
|
||||
/* */
|
||||
/* DOS-C is free software; you can redistribute it and/or */
|
||||
/* modify it under the terms of the GNU General Public License */
|
||||
/* as published by the Free Software Foundation; either version */
|
||||
/* 2, or (at your option) any later version. */
|
||||
/* */
|
||||
/* DOS-C is distributed in the hope that it will be useful, but */
|
||||
/* WITHOUT ANY WARRANTY; without even the implied warranty of */
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
|
||||
/* the GNU General Public License for more details. */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public */
|
||||
/* License along with DOS-C; see the file COPYING. If not, */
|
||||
/* write to the Free Software Foundation, 675 Mass Ave, */
|
||||
/* Cambridge, MA 02139, USA. */
|
||||
/****************************************************************/
|
||||
|
||||
/*
|
||||
current status:
|
||||
|
||||
load FreeDOS high, if DOS=HIGH detected
|
||||
|
||||
suppress High Loading, if any SHIFT status detected (for debugging)
|
||||
|
||||
if no XMS driver (HIMEM,FDXMS,...) loaded, should work
|
||||
|
||||
cooperation with XMS drivers as follows:
|
||||
|
||||
copy HMA_TEXT segment up.
|
||||
|
||||
after each loaded DEVICE=SOMETHING.SYS, try to request the HMA
|
||||
(XMS function 0x01).
|
||||
if no XMS driver detected, during ONFIG.SYS processing,
|
||||
create a dummy VDISK entry in high memory
|
||||
|
||||
this works with
|
||||
|
||||
FD FDXMS - no problems detected
|
||||
|
||||
|
||||
MS HIMEM.SYS (from DOS 6.2, 9-30-93)
|
||||
|
||||
works if and only if
|
||||
|
||||
/TESTMEM:OFF
|
||||
|
||||
is given
|
||||
|
||||
otherwise HIMEM will TEST AND ZERO THE HIGH MEMORY+HMA.
|
||||
so, in CONFIG.C, if "HIMEM.SYS" is detected, a "/TESTMEM:OFF"
|
||||
parameter is forced.
|
||||
*/
|
||||
|
||||
|
||||
#include "init-mod.h"
|
||||
|
||||
#include "portab.h"
|
||||
#include "globals.h"
|
||||
|
||||
#ifdef VERSION_STRINGS
|
||||
static BYTE *RcsId = "$Id$";
|
||||
#endif
|
||||
|
||||
/*
|
||||
* $Log$
|
||||
* Revision 1.1 2001/03/21 03:01:45 bartoldeman
|
||||
* New file by Tom Ehlert for HMA initialization.
|
||||
*
|
||||
* Revision 0.1 2001/03/16 12:00:00 tom ehlert
|
||||
* initial creation
|
||||
*/
|
||||
|
||||
|
||||
BYTE DosLoadedInHMA; /* set to TRUE if loaded HIGH */
|
||||
BYTE HMAclaimed; /* set to TRUE if claimed from HIMEM */
|
||||
WORD HMAFree; /* first byte in HMA not yet used */
|
||||
|
||||
|
||||
extern BYTE FAR * FAR XMSDriverAddress;
|
||||
extern FAR _EnableA20();
|
||||
extern FAR _DisableA20();
|
||||
|
||||
|
||||
void FAR *DetectXMSDriver();
|
||||
|
||||
#ifdef DEBUG
|
||||
#define int3() __int__(3);
|
||||
#else
|
||||
#define int3()
|
||||
#endif
|
||||
|
||||
|
||||
#if defined( DEBUG ) || 1 /* experimental kernel !! */
|
||||
#define HMAInitPrintf(x) printf x
|
||||
#else
|
||||
#define HMAInitPrintf(x)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
hdump(BYTE FAR *p)
|
||||
{
|
||||
int loop;
|
||||
HMAInitPrintf(("%p", p));
|
||||
|
||||
for (loop = 0; loop < 16; loop++)
|
||||
HMAInitPrintf(("%02x ", p[loop]));
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
#else
|
||||
#define hdump(ptr)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __TURBOC__
|
||||
void __int__(int); /* TC 2.01 requires this. :( -- ror4 */
|
||||
unsigned char __inportb__(int portid);
|
||||
void __outportb__ (int portid, unsigned char value);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define KeyboardShiftState() (*(BYTE FAR *)(MK_FP(0x40,0x17)))
|
||||
|
||||
|
||||
/* of course, this should go to ASMSUPT */
|
||||
fmemcmp(BYTE far *s1, BYTE FAR *s2, unsigned len)
|
||||
{
|
||||
for ( ; len ; s1++,s2++,--len)
|
||||
{
|
||||
if (*s1 - *s2)
|
||||
return *s1-*s2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Enable / Disable borrowed without understanding from FDXMS. Thanks.
|
||||
gone done to KERNEL.ASM
|
||||
|
||||
OutportWithDelay(WORD port, BYTE val)
|
||||
{
|
||||
int loop;
|
||||
|
||||
__outportb__(port,val);
|
||||
|
||||
for (loop = 100; --loop && __inportb__(0x64) & 0x02;)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
void _EnableHMA()
|
||||
{
|
||||
OutportWithDelay(0x64, 0xd1);
|
||||
OutportWithDelay(0x60, 0xdf);
|
||||
OutportWithDelay(0x64, 0xff);
|
||||
}
|
||||
void _DisableHMA()
|
||||
{
|
||||
OutportWithDelay(0x64, 0xd1);
|
||||
OutportWithDelay(0x60, 0xdd);
|
||||
OutportWithDelay(0x64, 0xff);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
this tests, if the HMA area can be enabled.
|
||||
if so, it simply leaves it on
|
||||
*/
|
||||
|
||||
int EnableHMA()
|
||||
{
|
||||
|
||||
_EnableA20();
|
||||
|
||||
if (fmemcmp(MK_FP(0x0000,0x0000), MK_FP(0xffff,0x0010),128) == 0)
|
||||
{
|
||||
printf("HMA can't be enabled\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
_DisableA20();
|
||||
|
||||
if (fmemcmp(MK_FP(0x0000,0x0000), MK_FP(0xffff,0x0010),128) != 0)
|
||||
{
|
||||
printf("HMA can't be disabled - no problem for us\n");
|
||||
}
|
||||
|
||||
_EnableA20();
|
||||
if (fmemcmp(MK_FP(0x0000,0x0000), MK_FP(0xffff,0x0010),128) == 0)
|
||||
{
|
||||
printf("HMA can't be enabled second time\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
HMAInitPrintf(("HMA success - leaving enabled\n"));
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
move the kernel up to high memory
|
||||
this is very unportable
|
||||
|
||||
if we thin we succeeded, we return TRUE, else FALSE
|
||||
*/
|
||||
|
||||
#define HMAOFFSET 0x20
|
||||
#define HMASEGMENT 0xffff
|
||||
|
||||
|
||||
int MoveKernelToHMA()
|
||||
{
|
||||
UBYTE FAR *HMASource;
|
||||
unsigned len;
|
||||
|
||||
|
||||
int3();
|
||||
|
||||
|
||||
if (DosLoadedInHMA)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
{ /* is very improbable - we are just booting - but
|
||||
there might already a XMS handler installed
|
||||
this is the case for DOSEMU
|
||||
*/
|
||||
|
||||
void FAR *pXMS = DetectXMSDriver();
|
||||
|
||||
if (pXMS != NULL)
|
||||
{
|
||||
XMSDriverAddress = pXMS;
|
||||
|
||||
printf("DOSEMU ? detected XMS driver at %p\n", XMSDriverAddress);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* A) for debugging purpose, suppress this,
|
||||
if any shift key is pressed
|
||||
*/
|
||||
|
||||
if (KeyboardShiftState() & 0x0f)
|
||||
{
|
||||
printf("Keyboard state is %0x, NOT moving to HMA\n",KeyboardShiftState());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* B) check out, if we can have HMA */
|
||||
|
||||
if (!EnableHMA())
|
||||
{
|
||||
printf("Can't enable HMA area (the famous A20), NOT moving to HMA\n");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* C) we have HMA, copy HMA_TEXT up to 0xffff:0..ffff */
|
||||
|
||||
{
|
||||
|
||||
UBYTE FAR *HMADest = MK_FP(HMASEGMENT,0x0000);
|
||||
|
||||
len = FP_OFF(_HMATextEnd) - FP_OFF(_HMATextStart);
|
||||
|
||||
HMASource = _HMATextStart;
|
||||
|
||||
|
||||
len += FP_OFF(HMASource) & 0x000f;
|
||||
|
||||
FP_OFF(HMASource) &= 0xfff0;
|
||||
|
||||
HMASource += HMAOFFSET;
|
||||
HMADest += HMAOFFSET;
|
||||
len -= HMAOFFSET;
|
||||
|
||||
|
||||
HMAInitPrintf(("HMA moving %p up to %p for %04x bytes\n",
|
||||
HMASource, HMADest, len));
|
||||
|
||||
fmemcpy(HMADest, HMASource, len);
|
||||
|
||||
HMAFree = FP_OFF(HMADest)+len; /* first free byte after HMA_TEXT */
|
||||
|
||||
int3();
|
||||
|
||||
}
|
||||
{
|
||||
/* D) but it only makes sense, if we can relocate
|
||||
all our entries to make use of HMA
|
||||
*/
|
||||
|
||||
/* this is for a
|
||||
call near enableA20
|
||||
jmp far kernelentry
|
||||
style table
|
||||
*/
|
||||
|
||||
struct RelocationTable {
|
||||
UBYTE jmpFar;
|
||||
UWORD jmpOffset;
|
||||
UWORD jmpSegment;
|
||||
UBYTE callNear;
|
||||
UWORD callOffset;
|
||||
};
|
||||
struct RelocatedEntry {
|
||||
UBYTE callNear;
|
||||
UWORD callOffset;
|
||||
UBYTE jmpFar;
|
||||
UWORD jmpOffset;
|
||||
UWORD jmpSegment;
|
||||
};
|
||||
extern struct RelocationTable
|
||||
FAR _HMARelocationTableStart[],
|
||||
FAR _HMARelocationTableEnd[];
|
||||
|
||||
struct RelocationTable FAR *rp, rtemp ;
|
||||
|
||||
|
||||
UWORD HMATextSegment = FP_SEG( _HMATextStart );
|
||||
|
||||
/* verify, that all entries are valid */
|
||||
|
||||
for (rp = _HMARelocationTableStart; rp < _HMARelocationTableEnd; rp++)
|
||||
{
|
||||
if (rp->jmpFar != 0xea || /* jmp FAR */
|
||||
rp->jmpSegment != HMATextSegment || /* will only relocate HMA_TEXT */
|
||||
rp->callNear != 0xe8 || /* call NEAR */
|
||||
0)
|
||||
{
|
||||
printf("illegal relocation entry # %d\n",rp - _HMARelocationTableStart);
|
||||
goto errorReturn;
|
||||
}
|
||||
}
|
||||
|
||||
/* OK, all valid, go to relocate*/
|
||||
|
||||
for (rp = _HMARelocationTableStart; rp < _HMARelocationTableEnd; rp++)
|
||||
{
|
||||
struct RelocatedEntry FAR *rel = (struct RelocatedEntry FAR *)rp;
|
||||
|
||||
fmemcpy(&rtemp, rp, sizeof(rtemp));
|
||||
|
||||
rel->jmpFar = rtemp.jmpFar;
|
||||
rel->jmpSegment = HMASEGMENT;
|
||||
rel->jmpOffset = rtemp.jmpOffset;
|
||||
rel->callNear = rtemp.callNear;
|
||||
rel->callOffset = rtemp.callOffset+5; /* near calls are relative */
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
/* E) up to now, nothing really bad was done.
|
||||
but now, we reuse the HMA area. bad things will happen
|
||||
|
||||
to find bugs early,
|
||||
cause INT 3 on all accesses to this area
|
||||
*/
|
||||
|
||||
fmemset(HMASource, 0xcc, len);
|
||||
HMAInitPrintf(("HMA text segment filled with INT 3\n"));
|
||||
|
||||
DosLoadedInHMA = TRUE;
|
||||
}
|
||||
|
||||
int3();
|
||||
return TRUE;
|
||||
|
||||
errorReturn:
|
||||
printf("HMA errors, not doing HMA\n");
|
||||
int3();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
now protect against HIMEM/FDXMS/... by simulating a VDISK
|
||||
FDXMS should detect us and not give HMA access to ohers
|
||||
unfortunately this also disables HIMEM completely
|
||||
|
||||
so: we install this after all drivers have been loaded
|
||||
*/
|
||||
void InstallVDISK()
|
||||
{
|
||||
static struct { /* Boot-Sektor of a RAM-Disk */
|
||||
BYTE dummy1[3]; /* HIMEM.SYS uses 3, but FDXMS uses 2 */
|
||||
char Name[5];
|
||||
BYTE dummy2[3];
|
||||
WORD BpS;
|
||||
BYTE dummy3[6];
|
||||
WORD Sektoren;
|
||||
BYTE dummy4;
|
||||
} VDISK_BOOT_SEKTOR =
|
||||
{
|
||||
{ 0xcf, ' ', ' '},
|
||||
{ 'V', 'D', 'I', 'S', 'K'},
|
||||
{ ' ', ' ', ' '},
|
||||
512,
|
||||
{ 'F', 'D', 'O', 'S', ' ', ' '},
|
||||
128, /* 128*512 = 64K */
|
||||
' '
|
||||
};
|
||||
|
||||
if (!DosLoadedInHMA) return;
|
||||
if (HMAclaimed) return;
|
||||
|
||||
|
||||
fmemcpy(MK_FP(0xffff,0x0010), &VDISK_BOOT_SEKTOR, sizeof(VDISK_BOOT_SEKTOR));
|
||||
|
||||
setvec(0x19, MK_FP(0xffff,0x0010)); /* let INT 19 point to VDISK */
|
||||
|
||||
}
|
||||
|
||||
|
||||
int init_call_XMScall( void FAR * driverAddress, UWORD ax, UWORD dx);
|
||||
void init_call_intr(int intrnr, iregs *rp);
|
||||
|
||||
|
||||
/*
|
||||
after each driver, we try to allocate the HMA.
|
||||
it might be HIMEM.SYS we just loaded.
|
||||
*/
|
||||
|
||||
void ClaimHMA()
|
||||
{
|
||||
void FAR *pXMS;
|
||||
|
||||
if (!DosLoadedInHMA) return;
|
||||
if (HMAclaimed) return;
|
||||
|
||||
|
||||
pXMS = DetectXMSDriver();
|
||||
|
||||
if (pXMS != NULL)
|
||||
{
|
||||
XMSDriverAddress = pXMS;
|
||||
|
||||
if (init_call_XMScall( pXMS, 0x0100, 0xffff))
|
||||
{
|
||||
printf("HMA area successfully claimed\n");
|
||||
HMAclaimed = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
void FAR *DetectXMSDriver()
|
||||
{
|
||||
iregs regs;
|
||||
|
||||
regs.a.x = 0x4300; /* XMS installation check */
|
||||
init_call_intr(0x2f, ®s);
|
||||
|
||||
if ((regs.a.x & 0xff) != 0x80) return NULL;
|
||||
|
||||
regs.a.x = 0x4310; /* XMS get driver address */
|
||||
init_call_intr(0x2f, ®s);
|
||||
|
||||
return MK_FP(regs.es, regs.b.x);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
this should be called, after each device driver
|
||||
has been loaded with FALSE
|
||||
and on finished CONFIG processing with TRUE.
|
||||
|
||||
will try to grab HMA;
|
||||
|
||||
on finalize, will install a VDISK
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void HMAconfig(int finalize)
|
||||
{
|
||||
ClaimHMA();
|
||||
|
||||
if (finalize)
|
||||
InstallVDISK();
|
||||
}
|
||||
|
||||
/*
|
||||
this allocates some bytes from the HMA area
|
||||
only available if DOS=HIGH was successful
|
||||
*/
|
||||
|
||||
VOID FAR *HMAalloc(COUNT bytesToAllocate)
|
||||
{
|
||||
VOID FAR *HMAptr;
|
||||
|
||||
if (!DosLoadedInHMA) return NULL;
|
||||
|
||||
if (HMAFree >= 0xfff0 - bytesToAllocate) return NULL;
|
||||
|
||||
HMAptr = MK_FP(0xffff, HMAFree);
|
||||
|
||||
HMAFree += bytesToAllocate;
|
||||
|
||||
/*printf("HMA allocated %d byte at %x\n", bytesToAllocate, HMAptr); */
|
||||
|
||||
return HMAptr;
|
||||
}
|
||||
|
Loading…
Reference in New Issue