/*++ 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 #include #include // 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)); }