You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1544 lines
33 KiB
1544 lines
33 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Monitor.c
|
|
Abstract:
|
|
|
|
This module is the user mode portion of the x86 monitor
|
|
|
|
Author:
|
|
|
|
Dave Hastings (daveh) 16 Mar 1991
|
|
|
|
Environment:
|
|
|
|
User mode only
|
|
|
|
Revision History:
|
|
William Hsieh 10-10-1992 Added A20 wrapping support
|
|
--*/
|
|
|
|
#define VDD_INTEG 1
|
|
#include "monitorp.h"
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <malloc.h>
|
|
|
|
// Tim Nov 92.
|
|
void sas_connect_memory(
|
|
IN sys_addr Low,
|
|
IN sys_addr High,
|
|
IN int Type
|
|
);
|
|
|
|
//BUGBUGBUGBUG Include file
|
|
|
|
// from base\inc\sas.h
|
|
/* memory types for sas */
|
|
#define SAS_RAM 0
|
|
#define SAS_VIDEO 1
|
|
#define SAS_ROM 2
|
|
#define SAS_WRAP 3
|
|
#define SAS_INACCESSIBLE 4
|
|
#define SAS_MAX_TYPE SAS_INACCESSIBLE
|
|
|
|
#define SIXTYFOURK 0x10000L
|
|
#define ONEMEGA 0x100000L
|
|
|
|
void rom_init();
|
|
void rom_checksum();
|
|
void copyROM();
|
|
|
|
USHORT get_lim_backfill_segment(void);
|
|
BOOL HoldEMMBackFillMemory(ULONG Address, ULONG Size);
|
|
|
|
#if DBG
|
|
extern unsigned short get_emm_page_size(void);
|
|
extern unsigned short get_intel_page_size(void);
|
|
#endif
|
|
|
|
/* SYNC THESE DEFINITIONS WITH BASE\EMM.H, or sas_init will assert */
|
|
#define EMM_PAGE_SIZE 0x4000
|
|
#define INTEL_PAGE_SIZE 0x1000
|
|
|
|
typedef struct
|
|
{
|
|
ULONG (*b_read) ();
|
|
ULONG (*w_read) ();
|
|
VOID (*str_read) ();
|
|
} READ_POINTERS;
|
|
|
|
// Internal Data
|
|
PMEMTYPE MemType = NULL;
|
|
|
|
// External Data
|
|
extern READ_POINTERS read_pointers;
|
|
|
|
// M variables used by video.lib
|
|
|
|
host_addr Start_of_M_area; /* host addr (char *) of start of M */
|
|
sys_addr Length_of_M_area; /* sys addr (long) offset of end of M */
|
|
|
|
static HANDLE A20SectionHandle = NULL;
|
|
static BOOL A20IsON = FALSE;
|
|
static USHORT BackFillSegment;
|
|
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_init(
|
|
IN sys_addr Size
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the SAS module, and allocates the linear
|
|
address space for the VDM, and loads the ROM
|
|
|
|
Arguments:
|
|
|
|
Size - Supplies the size of the VDMs linear address space.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG ViewSize;
|
|
PVOID BaseAddress;
|
|
OBJECT_ATTRIBUTES A20ObjAttr;
|
|
LARGE_INTEGER SectionSize;
|
|
USHORT Pages;
|
|
ULONG BackFillBase;
|
|
|
|
|
|
InitializeObjectAttributes(
|
|
&A20ObjAttr,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
SectionSize.HighPart = 0L;
|
|
SectionSize.LowPart = 640 * 1024 + 64 * 1024;
|
|
|
|
Status = NtCreateSection(
|
|
&A20SectionHandle,
|
|
SECTION_MAP_WRITE|SECTION_MAP_EXECUTE,
|
|
&A20ObjAttr,
|
|
&SectionSize,
|
|
PAGE_EXECUTE_READWRITE,
|
|
SEC_RESERVE,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
// bugbug -williamh
|
|
// we should pop up an approiate message before we
|
|
// terminate the vdm.
|
|
#if DBG
|
|
DbgPrint("sas_init: can not create himem section, status = %lx\n",
|
|
Status);
|
|
#endif
|
|
TerminateVDM();
|
|
}
|
|
VdmSize = Size;
|
|
|
|
//
|
|
// N.B. We expect that process creation has reserved the first 16 MB
|
|
// for us already. If not, then this won't work worth a darn
|
|
|
|
// free the first 640KB virtual address.
|
|
// This is done because it has been resevered before sas_init get called
|
|
BaseAddress = (PVOID)1;
|
|
ViewSize = 640 * 1024 - 1;
|
|
Status = NtFreeVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
&ViewSize,
|
|
MEM_RELEASE
|
|
);
|
|
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("sas_init: cannot free 1st 640k virtual address, status = %lx\n",
|
|
Status);
|
|
#endif
|
|
TerminateVDM();
|
|
}
|
|
|
|
BaseAddress =(PVOID) ONEMEGA;
|
|
ViewSize = SIXTYFOURK;
|
|
Status = NtFreeVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
&ViewSize,
|
|
MEM_RELEASE
|
|
);
|
|
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("sas_init: can not free himem virtual address, status = %lx\n",
|
|
Status);
|
|
#endif
|
|
TerminateVDM();
|
|
}
|
|
|
|
BaseAddress = (PVOID)VDM_BASE_ADDRESS;
|
|
ViewSize = SIXTYFOURK - (ULONG)VDM_BASE_ADDRESS;
|
|
SectionSize.HighPart = SectionSize.LowPart = 0;
|
|
|
|
Status = NtMapViewOfSection(
|
|
A20SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
ViewSize,
|
|
&SectionSize,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
MEM_DOS_LIM,
|
|
PAGE_EXECUTE_READWRITE
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)){
|
|
#if DBG
|
|
DbgPrint("sas_init: can not map view of 1st 64K, status = %ls\n",
|
|
Status);
|
|
#endif
|
|
TerminateVDM();
|
|
}
|
|
BaseAddress = (PVOID) ONEMEGA;
|
|
ViewSize = SIXTYFOURK;
|
|
Status = NtMapViewOfSection(A20SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
ViewSize,
|
|
&SectionSize,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
MEM_DOS_LIM,
|
|
PAGE_EXECUTE_READWRITE
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)){
|
|
#if DBG
|
|
DbgPrint("sas_init: can not map view of himem space, status = %lx\n",
|
|
Status);
|
|
#endif
|
|
TerminateVDM();
|
|
}
|
|
|
|
// get emm back fill segment address from softpc
|
|
// we cut the backfill memory area into pieces in EMM_PAGE_SIZE unit.
|
|
// this is done so that EMM manager can grab the address space
|
|
// as EMM page frame.
|
|
// note that if EMM is disabled, the backfill segment will be
|
|
// (640 * 1024 / 16).
|
|
|
|
BackFillSegment = get_lim_backfill_segment();
|
|
|
|
ASSERT(BackFillSegment <= 640 * 1024 / 16);
|
|
|
|
//
|
|
// Map the rest of conventional memory
|
|
// only map up to the emm backfill segment.
|
|
BaseAddress = (PVOID) (64 * 1024);
|
|
ViewSize = BackFillSegment * 16 - 64 * 1024;
|
|
SectionSize.LowPart = 64 * 1024;
|
|
SectionSize.HighPart = 0;
|
|
Status = NtMapViewOfSection(A20SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
ViewSize,
|
|
&SectionSize,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
MEM_DOS_LIM,
|
|
PAGE_EXECUTE_READWRITE
|
|
);
|
|
if (!NT_SUCCESS(Status)){
|
|
#if DBG
|
|
DbgPrint("sas_init: can not map view of himem space, status = %lx\n",
|
|
Status);
|
|
#endif
|
|
TerminateVDM();
|
|
}
|
|
|
|
// if there are any backfill memory, map it to our section initially
|
|
if (BackFillSegment < 640 * 1024 / 16) {
|
|
|
|
/* make sure our constants are in sync with emm.h */
|
|
#if DBG
|
|
ASSERT(EMM_PAGE_SIZE == get_emm_page_size());
|
|
ASSERT(INTEL_PAGE_SIZE == get_intel_page_size());
|
|
#endif
|
|
if (!HoldEMMBackFillMemory(BackFillSegment * 16,
|
|
(640 * 1024) - BackFillSegment * 16)
|
|
) {
|
|
|
|
#if DBG
|
|
DbgPrint("sas_init: can not map backfill space, status = %lx\n",
|
|
Status);
|
|
#endif
|
|
TerminateVDM();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate ROM area
|
|
//
|
|
BaseAddress = (PVOID)(640 * 1024);
|
|
ViewSize = 384 * 1024;
|
|
Status = NtAllocateVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0L,
|
|
&ViewSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE
|
|
);
|
|
if (!NT_SUCCESS(Status)){
|
|
#if DBG
|
|
DbgPrint("sas_init: can not map view of himem space, status = %lx\n",
|
|
Status);
|
|
#endif
|
|
TerminateVDM();
|
|
}
|
|
|
|
A20IsON = FALSE;
|
|
|
|
Start_of_M_area = 0;
|
|
Length_of_M_area = VdmSize;
|
|
sas_connect_memory(0, VdmSize + 2*SIXTYFOURK -1, SAS_RAM);
|
|
}
|
|
|
|
#if VDD_INTEG
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_term(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free memory prior to reallocing it
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
PVOID BaseAddress;
|
|
NTSTATUS Status;
|
|
ULONG Size;
|
|
|
|
BaseAddress = (PVOID)VDM_BASE_ADDRESS;
|
|
Size = VdmSize;
|
|
Status = NtFreeVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
&Size,
|
|
MEM_DECOMMIT);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
VDprint(VDP_LEVEL_ERROR,
|
|
("SoftPc: NtDeCommitVirtualMemory failed !!!! Status = %lx\n",
|
|
Status));
|
|
VDbreak(VDB_LEVEL_ERROR);
|
|
}
|
|
}
|
|
|
|
|
|
EXPORT
|
|
sys_addr
|
|
sas_memory_size(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the size of Intel memory
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
size of intel memory
|
|
|
|
--*/
|
|
{
|
|
return(VdmSize);
|
|
}
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_connect_memory(
|
|
IN sys_addr Low,
|
|
IN sys_addr High,
|
|
IN int Type
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets up a type record for the specified address region.
|
|
If the specified address region was a different type, it is changed to
|
|
the new type.
|
|
|
|
Arguments:
|
|
|
|
Low -- the starting address of the region
|
|
High -- the ending address of the region
|
|
Type -- the type for the region, one of SAS_RAM, SAS_VIDEO, SAS_ROM,
|
|
SAS_WRAP, SAS_INACCESSIBLE
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
//bugbug do we handle new block contained in old block correctly?
|
|
PMEMTYPE Current, Previous, New, Temp;
|
|
|
|
if (!MemType) {
|
|
MemType = (PMEMTYPE) ch_malloc(sizeof(MEMTYPE));
|
|
if ( NULL == MemType ) {
|
|
goto ErrorSASC;
|
|
}
|
|
|
|
MemType->Previous = NULL;
|
|
MemType->Next = NULL;
|
|
MemType->Start = Low;
|
|
MemType->End = High;
|
|
MemType->Type = (half_word)Type;
|
|
return;
|
|
}
|
|
|
|
Current = MemType;
|
|
while (Current && (Low > Current->Start)) {
|
|
Previous = Current;
|
|
Current = Current->Next;
|
|
}
|
|
|
|
if ((Current) && (Low == Current->Start) && (High == Current->End)) {
|
|
Current->Type = (half_word)Type;
|
|
return;
|
|
}
|
|
|
|
New = (PMEMTYPE) ch_malloc(sizeof(MEMTYPE));
|
|
if ( NULL == New ) {
|
|
goto ErrorSASC;
|
|
}
|
|
|
|
if (!Current) {
|
|
// Block goes at end of list
|
|
|
|
Previous->Next = New;
|
|
New->Previous = Previous;
|
|
New->Start = Low;
|
|
New->End = High;
|
|
New->Type = (half_word)Type;
|
|
New->Next = NULL;
|
|
} else {
|
|
// Block goes in front of Current
|
|
|
|
New->Start = Low;
|
|
New->Type = (half_word)Type;
|
|
New->End = High;
|
|
New->Previous = Current->Previous;
|
|
New->Next = Current;
|
|
Current->Previous = New;
|
|
if (!New->Previous) {
|
|
MemType = New;
|
|
} else {
|
|
New->Previous->Next = New;
|
|
}
|
|
}
|
|
|
|
|
|
// Block overlaps one or more existing blocks
|
|
|
|
if (New->Previous) {
|
|
if (New->Previous->End > New->End) {
|
|
// block contained in exising block
|
|
Temp = (PMEMTYPE) ch_malloc(sizeof(MEMTYPE));
|
|
if(NULL == Temp) {
|
|
goto ErrorSASC;
|
|
}
|
|
Temp->Previous = New;
|
|
Temp->Next = New->Next;
|
|
New->Next = Temp;
|
|
if (Temp->Next) {
|
|
Temp->Next->Previous = Temp;
|
|
}
|
|
Temp->End = New->Previous->End;
|
|
New->Previous->End = New->Start - 1;
|
|
Temp->Start = New->End + 1;
|
|
Temp->Type = New->Previous->Type;
|
|
return;
|
|
} else if (New->Previous->End >= New->Start){
|
|
// block overlaps end of exising block
|
|
New->Previous->End = New->Start - 1;
|
|
}
|
|
}
|
|
|
|
// remove all blocks entirely contained in new block
|
|
while ((New->Next) && (New->Next->End <= New->End)) {
|
|
Temp = New->Next;
|
|
New->Next = New->Next->Next;
|
|
if (New->Next) {
|
|
New->Next->Previous = New;
|
|
}
|
|
free(Temp);
|
|
}
|
|
|
|
// remove portion of next block overlapping new block
|
|
if ((New->Next) && (New->Next->Start <= New->End)) {
|
|
New->Next->Start = New->End + 1;
|
|
}
|
|
return;
|
|
ErrorSASC:
|
|
|
|
RcMessageBox(EG_MALLOC_FAILURE, NULL, NULL,
|
|
RMB_ICON_BANG | RMB_ABORT);
|
|
TerminateVDM();
|
|
}
|
|
|
|
EXPORT
|
|
half_word
|
|
sas_memory_type(
|
|
IN sys_addr Address
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the type of memory at a specific address
|
|
|
|
Arguments:
|
|
|
|
Address -- linear address to return type for.
|
|
|
|
Return Value:
|
|
|
|
the type for the region, one of SAS_RAM, SAS_VIDEO, SAS_ROM,
|
|
SAS_WRAP, SAS_INACCESSIBLE
|
|
--*/
|
|
{
|
|
PMEMTYPE Current;
|
|
|
|
if (Address > VdmSize) {
|
|
return SAS_INACCESSIBLE;
|
|
}
|
|
|
|
Current = MemType;
|
|
while (Current && !((Address >= Current->Start) &&
|
|
(Address <= Current->End))) {
|
|
Current = Current->Next;
|
|
}
|
|
if (!Current) {
|
|
return SAS_INACCESSIBLE;
|
|
}
|
|
return Current->Type;
|
|
}
|
|
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_enable_20_bit_wrapping(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine causes memory addresses to wrap at 1MB
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
ULONG Size;
|
|
LARGE_INTEGER SectionOffset;
|
|
// if A20 line is off already do nothing
|
|
if (A20IsON == FALSE){
|
|
return;
|
|
}
|
|
BaseAddress = (PVOID)ONEMEGA;
|
|
Size = SIXTYFOURK;
|
|
Status = NtUnmapViewOfSection(NtCurrentProcess(),
|
|
BaseAddress
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("A20OFF: Unable to unmap view of section, status = %lx\n",
|
|
Status);
|
|
#endif
|
|
TerminateVDM();
|
|
}
|
|
SectionOffset.HighPart = SectionOffset.LowPart = 0;
|
|
Status = NtMapViewOfSection(A20SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
Size,
|
|
&SectionOffset,
|
|
&Size,
|
|
ViewUnmap,
|
|
MEM_DOS_LIM,
|
|
PAGE_EXECUTE_READWRITE
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("A20OFF: Unable to map view of section, status = %lx\n",
|
|
Status);
|
|
#endif
|
|
TerminateVDM();
|
|
}
|
|
A20IsON = FALSE;
|
|
}
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_disable_20_bit_wrapping(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine causes addressing to NOT wrap at 1MB
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
ULONG Size;
|
|
LARGE_INTEGER SectionOffset;
|
|
|
|
// if A20 line is on already do nothing
|
|
if (A20IsON == TRUE){
|
|
return;
|
|
}
|
|
BaseAddress = (PVOID)ONEMEGA;
|
|
Size = SIXTYFOURK;
|
|
|
|
Status = NtUnmapViewOfSection(NtCurrentProcess(),
|
|
BaseAddress
|
|
);
|
|
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("A20ON: Unable to unmap view of section, status = %lx\n",
|
|
Status);
|
|
#endif
|
|
TerminateVDM();
|
|
}
|
|
SectionOffset.HighPart = 0;
|
|
SectionOffset.LowPart = 640 * 1024;
|
|
Status = NtMapViewOfSection(A20SectionHandle,
|
|
NtCurrentProcess(),
|
|
&BaseAddress,
|
|
0,
|
|
Size,
|
|
&SectionOffset,
|
|
&Size,
|
|
ViewUnmap,
|
|
MEM_DOS_LIM,
|
|
PAGE_EXECUTE_READWRITE
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
#if DBG
|
|
DbgPrint("A20ON: Unable to map view of section, status = %lx\n",
|
|
Status);
|
|
#endif
|
|
TerminateVDM();
|
|
}
|
|
A20IsON = TRUE;
|
|
}
|
|
|
|
|
|
|
|
EXPORT
|
|
half_word
|
|
sas_hw_at(
|
|
IN sys_addr Address
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the byte at the specified address
|
|
|
|
Arguments:
|
|
|
|
Address -- address of byte to return
|
|
|
|
Return Value:
|
|
|
|
value of byte at specified address
|
|
|
|
--*/
|
|
{
|
|
half_word RetVal;
|
|
|
|
if (Address > VdmSize) {
|
|
return 0xFE;
|
|
}
|
|
|
|
RetVal = *((half_word *)Address);
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
EXPORT
|
|
word
|
|
sas_w_at(
|
|
IN sys_addr Address
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the word at the specified address
|
|
|
|
Arguments:
|
|
|
|
Address -- address of word to return
|
|
|
|
Return Value:
|
|
|
|
value of word at specified address
|
|
|
|
--*/
|
|
{
|
|
word RetVal;
|
|
|
|
// DbgPrint("NtVdm : sas_w_at \n");
|
|
if (Address > VdmSize) {
|
|
return 0xFEFE;
|
|
}
|
|
|
|
RetVal = *((word *)Address);
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
EXPORT
|
|
double_word
|
|
sas_dw_at(
|
|
IN sys_addr Address
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the dword at the specified address
|
|
|
|
Arguments:
|
|
|
|
Address -- address of dword to return
|
|
|
|
Return Value:
|
|
|
|
value of dword at specified address
|
|
|
|
--*/
|
|
{
|
|
double_word RetVal;
|
|
|
|
//DbgPrint("NtVdm : sas_dw_at \n");
|
|
RetVal = (double_word)(((ULONG)sas_w_at(Address + 2) << 16) +
|
|
sas_w_at(Address));
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_load(
|
|
IN sys_addr Address,
|
|
IN half_word *Value
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stores the byte at the specified address in the supplied
|
|
variable
|
|
|
|
Arguments:
|
|
|
|
Address -- address of byte to return
|
|
Value -- Variable to store the value in
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
//DbgPrint("NtVdm : sas_load \n");
|
|
if (Address > VdmSize) {
|
|
*Value = 0xFE;
|
|
return;
|
|
}
|
|
|
|
*Value = *((half_word *)Address);
|
|
return;
|
|
}
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_loadw(
|
|
IN sys_addr Address,
|
|
IN word *Value
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stores the word at the specified address in the supplied
|
|
variable
|
|
|
|
Arguments:
|
|
|
|
Address -- address of word to return
|
|
Value -- Variable to store the value in
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
//DbgPrint("NtVdm : sas_loadw\n");
|
|
if (Address > VdmSize) {
|
|
*Value = 0xFEFE;
|
|
return;
|
|
}
|
|
|
|
*Value = *((word *)Address);
|
|
//DbgPrint("NtVdm : sas_loadw word at address %lx is %x (Not video)\n",Address,*Value);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_store(
|
|
IN sys_addr Address,
|
|
IN half_word Value
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stores the specified byte at the specified address
|
|
|
|
Arguments:
|
|
|
|
Address -- address of word to return
|
|
Value -- value to store
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
half_word Type;
|
|
//DbgPrint("NtVdm : sas_store\n");
|
|
if (Address <= VdmSize) {
|
|
Type = sas_memory_type(Address);
|
|
switch (Type) {
|
|
case SAS_ROM:
|
|
break;
|
|
|
|
default:
|
|
*((half_word *)Address) = Value;
|
|
//DbgPrint("NtVdm : sas_store put byte %x at address %lx\n",Value,Address);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_storew(
|
|
IN sys_addr Address,
|
|
IN word Value
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stores the specified word at the specified address
|
|
|
|
Arguments:
|
|
|
|
Address -- address of word to return
|
|
Value -- value to store at the specified address
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
|
|
//DbgPrint("NtVdm : sas_storew\n");
|
|
if (Address + 1 <= VdmSize) {
|
|
switch (sas_memory_type(Address)) {
|
|
|
|
case SAS_ROM:
|
|
break;
|
|
|
|
default:
|
|
*((word *)Address) = Value;
|
|
//DbgPrint("NtVdm : sas_storew put word %x at address %lx\n",Value,Address);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_storedw(
|
|
IN sys_addr Address,
|
|
IN double_word Value
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine stores the specified dword at the specified address
|
|
|
|
Arguments:
|
|
|
|
Address -- address of word to return
|
|
Value -- value to store at the specified address
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
//_asm int 3;
|
|
sas_storew(Address, (word)(Value & 0xFFFF));
|
|
sas_storew(Address + 2, (word)((Value >> 16) & 0xFFFF));
|
|
}
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_loads(
|
|
IN sys_addr Source,
|
|
IN host_addr Destination,
|
|
IN sys_addr Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies the string from the specified intel address to the
|
|
specified host address
|
|
|
|
Arguments:
|
|
|
|
Source -- Intel address to copy from
|
|
Destination -- host address to copy the string to
|
|
Length -- length of the string to copy
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
|
|
//DbgPrint("NtVdm : sas_loads\n");
|
|
RtlCopyMemory((PVOID) Destination, (PVOID) Source, Length);
|
|
}
|
|
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_stores(
|
|
IN sys_addr Destination,
|
|
IN host_addr Source,
|
|
IN sys_addr Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies the string from the specified host address to the
|
|
specified intel address
|
|
|
|
Arguments:
|
|
|
|
Destination -- intel address to copy the string to
|
|
Source -- host address to copy from
|
|
Length -- length of the string to copy
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
|
|
//DbgPrint("NtVdm : sas_stores\n");
|
|
switch (sas_memory_type(Destination)) {
|
|
|
|
case SAS_ROM:
|
|
break;
|
|
|
|
default:
|
|
RtlCopyMemory((PVOID) Destination, (PVOID) Source, Length);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_move_bytes_forward(
|
|
IN sys_addr Source,
|
|
IN sys_addr Destination,
|
|
IN sys_addr Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies one region of intel memory to another.
|
|
|
|
Arguments:
|
|
|
|
Source -- source intel address
|
|
Destination -- destination intel address
|
|
Length -- length of region to copy (in bytes)
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
//DbgPrint("NtVdm : sas_move_bytes_forward\n");
|
|
switch (sas_memory_type(Destination)) {
|
|
|
|
case SAS_ROM:
|
|
break;
|
|
|
|
default:
|
|
RtlCopyMemory((PVOID) Destination, (PVOID) Source, Length);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_move_words_forward(
|
|
IN sys_addr Source,
|
|
IN sys_addr Destination,
|
|
IN sys_addr Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies one region of intel memory to another.
|
|
|
|
Arguments:
|
|
|
|
Source -- source intel address
|
|
Destination -- destination intel address
|
|
Length -- length of region to copy (in words)
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
//_asm int 3;
|
|
Length <<= 1;
|
|
switch (sas_memory_type(Destination)) {
|
|
|
|
case SAS_ROM:
|
|
break;
|
|
|
|
default:
|
|
RtlCopyMemory((PVOID) Destination, (PVOID) Source, Length);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_move_bytes_backward(
|
|
IN sys_addr Source,
|
|
IN sys_addr Destination,
|
|
IN sys_addr Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies one region of intel memory to another.
|
|
|
|
Arguments:
|
|
|
|
Source -- source intel address
|
|
Destination -- destination intel address
|
|
Length -- length of region to copy (in bytes)
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
//_asm int 3;
|
|
switch (sas_memory_type(Destination)) {
|
|
|
|
case SAS_ROM:
|
|
break;
|
|
|
|
default:
|
|
RtlCopyMemory((PVOID) (Destination - Length + 1),
|
|
(PVOID) (Source - Length + 1),
|
|
Length);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_move_words_backward(
|
|
IN sys_addr Source,
|
|
IN sys_addr Destination,
|
|
IN sys_addr Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine copies one region of intel memory to another.
|
|
|
|
Arguments:
|
|
|
|
Source -- source intel address
|
|
Destination -- destination intel address
|
|
Length -- length of region to copy (in words)
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
//_asm int 3;
|
|
Length <<= 1;
|
|
switch (sas_memory_type(Destination)) {
|
|
|
|
case SAS_ROM:
|
|
break;
|
|
|
|
default:
|
|
RtlCopyMemory((PVOID) (Destination - Length + 1),
|
|
(PVOID) (Source - Length + 1),
|
|
Length);
|
|
break;
|
|
}
|
|
}
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_fills(
|
|
IN sys_addr Address,
|
|
IN half_word Value,
|
|
IN sys_addr Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine fills a specified region of intel memory with a byte value
|
|
|
|
Arguments:
|
|
|
|
Address -- address to fill at
|
|
Value -- value to fill with
|
|
Length -- length of region to fill
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
half_word Type;
|
|
|
|
//DbgPrint("NtVdm : sas_fills\n");
|
|
Type = sas_memory_type(Address);
|
|
switch (Type) {
|
|
|
|
case SAS_ROM:
|
|
break;
|
|
|
|
default:
|
|
RtlFillMemory((PVOID) Address, Length, Value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_fillsw(
|
|
IN sys_addr Address,
|
|
IN word Value,
|
|
IN sys_addr Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine fills a specified region of intel memory with a word value
|
|
|
|
Arguments:
|
|
|
|
Address -- address to fill at
|
|
Value -- value to fill with
|
|
Length -- length of region to fill
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
|
|
word *p;
|
|
half_word Type;
|
|
|
|
//DbgPrint("NtVdm : sas_fillsw\n");
|
|
Type = sas_memory_type(Address);
|
|
switch (Type) {
|
|
|
|
case SAS_ROM:
|
|
break;
|
|
|
|
default:
|
|
p = (word *)Address;
|
|
while (Length--) {
|
|
*p++ = Value;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
host_addr scratch = NULL;
|
|
|
|
EXPORT
|
|
host_addr
|
|
sas_scratch_address(
|
|
IN sys_addr Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine supplies a scratch buffer for short term use
|
|
|
|
Arguments
|
|
|
|
Length -- length of buffer needed
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
NOTE: Sudeepb 31-Oct-1993 Converted scratch to be allocated dynamically rather
|
|
than as a static array.
|
|
--*/
|
|
{
|
|
//DbgPrint("NtVdm : sas_scratch_address\n");
|
|
if (Length > 64 * 1024) {
|
|
return NULL;
|
|
}
|
|
|
|
if (scratch)
|
|
return scratch;
|
|
|
|
if ((scratch = (host_addr) malloc (64 * 1024)) == NULL){
|
|
RcMessageBox(EG_MALLOC_FAILURE, NULL, NULL,
|
|
RMB_ICON_BANG | RMB_ABORT);
|
|
TerminateVDM();
|
|
return NULL;
|
|
}
|
|
|
|
return scratch;
|
|
}
|
|
|
|
EXPORT
|
|
half_word
|
|
sas_hw_at_no_check(
|
|
sys_addr addr
|
|
)
|
|
// bugbug comment
|
|
{
|
|
//DbgPrint("NtVdm : sas_hw_at_no_check\n");
|
|
//DbgPrint("NtVdm : sas_hw_at_no_check byte at %lx is %x\n",addr,*((half_word *)addr));
|
|
return *((half_word *)addr);
|
|
}
|
|
|
|
EXPORT
|
|
word
|
|
sas_w_at_no_check(
|
|
sys_addr addr
|
|
)
|
|
// bugbug comment
|
|
{
|
|
//DbgPrint("NtVdm : sas_w_at_no_check\n");
|
|
//DbgPrint("NtVdm : sas_w_at_no_check word at %lx is %x\n",addr,*((word *)addr));
|
|
return *((word *)addr);
|
|
}
|
|
EXPORT
|
|
double_word
|
|
sas_dw_at_no_check(
|
|
sys_addr addr
|
|
)
|
|
// bugbug comment
|
|
{
|
|
//DbgPrint("NtVdm : sas_dw_at_no_check\n");
|
|
//DbgPrint("NtVdm : sas_dw_at_no_check double word at %lx is %lx\n",addr,*((double_word *)addr));
|
|
return *((double_word *)addr);
|
|
}
|
|
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_store_no_check(
|
|
sys_addr addr,
|
|
half_word val
|
|
)
|
|
// bugbug comment
|
|
{
|
|
//DbgPrint("NtVdm : sas_store_no_check\n");
|
|
*((half_word *)addr) = val;
|
|
//DbgPrint("NtVdm : sas_store_no_check stored byte %x at %lx\n",val,addr);
|
|
}
|
|
|
|
EXPORT
|
|
VOID
|
|
sas_storew_no_check(
|
|
sys_addr addr,
|
|
word val
|
|
)
|
|
// bugbug comment
|
|
{
|
|
//DbgPrint("NtVdm : sas_storew_no_check\n");
|
|
*((word *)addr) = val;
|
|
}
|
|
EXPORT
|
|
double_word
|
|
effective_addr(
|
|
IN word Segment,
|
|
IN word Offset
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine maps effective_addr to Sim32GetVdmPointer
|
|
|
|
Arguments:
|
|
|
|
Segment -- segment of address
|
|
Offset -- offset of address
|
|
|
|
Return Value:
|
|
|
|
Actual Intel address corresponding to the address supplied
|
|
--*/
|
|
{
|
|
//DbgPrint("NtVdm : effective_addr\n");
|
|
return (ULONG)Sim32GetVDMPointer(((((ULONG)Segment) << 16) | Offset), 1,
|
|
(UCHAR) (getMSW() & MSW_PE ? TRUE : FALSE));
|
|
}
|
|
|
|
typedef enum
|
|
{
|
|
RAM,
|
|
VIDEO,
|
|
ROM,
|
|
IN_FRAGMENT,
|
|
NEXT_FRAGMENT
|
|
} mem_type;
|
|
|
|
typedef struct
|
|
{
|
|
VOID (*b_write)();
|
|
VOID (*w_write)();
|
|
VOID (*b_fill)();
|
|
VOID (*w_fill)();
|
|
VOID (*b_move)();
|
|
VOID (*w_move)();
|
|
} MEM_HANDLERS;
|
|
#define TYPE_RANGE ((int)SAS_INACCESSIBLE)
|
|
#define write_b_write_ptrs( offset, func ) ( b_write_ptrs[(offset)] = (func) )
|
|
#define write_w_write_ptrs( offset, func ) ( w_write_ptrs[(offset)] = (func) )
|
|
#define write_b_page_ptrs( offset, func ) ( b_move_ptrs[(offset)] = b_fill_ptrs[(offset)] = (func) )
|
|
#define write_w_page_ptrs( offset, func ) ( w_move_ptrs[(offset)] = w_fill_ptrs[(offset)] = (func) )
|
|
#define init_b_write_ptrs( offset, func ) ( b_write_ptrs[(offset)] = (func) )
|
|
#define init_w_write_ptrs( offset, func ) ( w_write_ptrs[(offset)] = (func) )
|
|
#define init_b_page_ptrs( offset, func ) ( b_move_ptrs[(offset)] = b_fill_ptrs[(offset)] = (func) )
|
|
#define init_w_page_ptrs( offset, func ) ( w_move_ptrs[(offset)] = w_fill_ptrs[(offset)] = (func) )
|
|
#define read_b_write_ptrs( offset ) ( b_write_ptrs[(offset)] )
|
|
#define read_w_write_ptrs( offset ) ( w_write_ptrs[(offset)] )
|
|
#define read_b_page_ptrs( offset ) ( b_move_ptrs[(offset)] )
|
|
#define read_w_page_ptrs( offset ) ( w_move_ptrs[(offset)] )
|
|
#define read_b_move_ptrs( offset ) ( b_move_ptrs[(offset)] )
|
|
#define read_w_move_ptrs( offset ) ( w_move_ptrs[(offset)] )
|
|
#define read_b_fill_ptrs( offset ) ( b_fill_ptrs[(offset)] )
|
|
#define read_w_fill_ptrs( offset ) ( w_fill_ptrs[(offset)] )
|
|
|
|
/*
|
|
* The main gmi data structures are defined here
|
|
*/
|
|
void (*(b_write_ptrs[TYPE_RANGE]))() ; /* byte write function */
|
|
void (*(w_write_ptrs[TYPE_RANGE]))() ; /* word write function */
|
|
void (*(b_fill_ptrs[TYPE_RANGE]))() ; /* byte str fill func */
|
|
void (*(w_fill_ptrs[TYPE_RANGE]))() ; /* word str fill func */
|
|
void (*(b_move_ptrs[TYPE_RANGE]))() ; /* byte str write func */
|
|
void (*(w_move_ptrs[TYPE_RANGE]))() ; /* word str write func */
|
|
|
|
void gmi_define_mem(type,handlers)
|
|
mem_type type;
|
|
MEM_HANDLERS *handlers;
|
|
{
|
|
int int_type = (int)(type);
|
|
init_b_write_ptrs(int_type, (void(*)())(handlers->b_write));
|
|
init_w_write_ptrs(int_type, (void(*)())(handlers->w_write));
|
|
b_move_ptrs[int_type] = (void(*)())(handlers->b_move);
|
|
w_move_ptrs[int_type] = (void(*)())(handlers->w_move);
|
|
b_fill_ptrs[int_type] = (void(*)())(handlers->b_fill);
|
|
w_fill_ptrs[int_type] = (void(*)())(handlers->w_fill);
|
|
}
|
|
#endif
|
|
BOOL sas_twenty_bit_wrapping_enabled() {
|
|
return (!A20IsON);
|
|
}
|
|
|
|
VOID sas_part_enable_20_bit_wrapping(){
|
|
}
|
|
VOID sas_part_disable_20_bit_wrapping(){
|
|
}
|
|
|
|
|
|
/*
|
|
* This function maps the given EMM backfill memory to DOS conventional
|
|
* memory. The function is provided to EMM manager to put back
|
|
* unmapped backfill memory(hold its contents while it is not mapped).
|
|
*
|
|
* NOTE: The very first caller will be sas_init.
|
|
*
|
|
* Input: ULONG BaseAddress -- the starting address, must be in INTEL page
|
|
* boundary
|
|
* ULONG Size -- size of the range, must be a multiple of
|
|
* EMM_PAGE_SIZE.
|
|
*
|
|
* According to LouP, a view costs about 400 bytes of memory. This is why
|
|
* I make these function strictly to work on EMM_PAGE_SIZE instead of 4KB.
|
|
*/
|
|
|
|
|
|
BOOL
|
|
HoldEMMBackFillMemory(ULONG BaseAddress, ULONG Size)
|
|
{
|
|
ULONG NewBase, Pages, i;
|
|
LARGE_INTEGER SectionOffset;
|
|
ULONG ViewSize;
|
|
NTSTATUS Status = STATUS_SUCCESS;;
|
|
|
|
/* this function can only be called if there is backfill at all */
|
|
ASSERT(BackFillSegment < 640 * 1024 / 16);
|
|
|
|
// size must be EMM_PAGE_SIZE multiple
|
|
ASSERT((Size % EMM_PAGE_SIZE) == 0);
|
|
|
|
// address must be on INTEL page boundary
|
|
ASSERT((BaseAddress & (INTEL_PAGE_SIZE - 1)) == 0);
|
|
|
|
for (Pages = Size / EMM_PAGE_SIZE; Pages; Pages--) {
|
|
SectionOffset.LowPart = BaseAddress;
|
|
SectionOffset.HighPart = 0;
|
|
ViewSize = EMM_PAGE_SIZE;
|
|
Status = NtMapViewOfSection(A20SectionHandle,
|
|
NtCurrentProcess(),
|
|
(PVOID *)&BaseAddress,
|
|
0,
|
|
ViewSize,
|
|
&SectionOffset,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
MEM_DOS_LIM,
|
|
PAGE_EXECUTE_READWRITE
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
BaseAddress += EMM_PAGE_SIZE;
|
|
}
|
|
return (NT_SUCCESS(Status));
|
|
}
|