#include "insignia.h" #include "host_def.h" #ifdef SUN_VA #define MAXPATHLEN 1024 #define NL 0x0a #define CR 0x0d #include #endif /* INSIGNIA MODULE SPECIFICATION ----------------------------- MODULE NAME : 'Top layer' of Expanded Memory Manager THIS PROGRAM SOURCE FILE IS SUPPLIED IN CONFIDENCE TO THE CUSTOMER, THE CONTENTS OR DETAILS OF ITS OPERATION MUST NOT BE DISCLOSED TO ANY OTHER PARTIES WITHOUT THE EXPRESS AUTHORISATION FROM THE DIRECTORS OF INSIGNIA SOLUTIONS INC. DESIGNER : J.P.Box DATE : May '88 PURPOSE : Contains all the top level calls to the Expanded Memory Manager. Data is received and returned to the calling application via Intel registers The Following Routines are defined: 0. emm_io() 1. Get_Status() 2. Get_Page_Frame_Address() 3. Get_Unallocated_Page() 4. Allocate_Pages() 5. Map_Unmap_Handle_Page() 6. Deallocate_Pages() 7. Get_Version() 8. Save_Page_Map() 9. Restore_Page_Map() 10. Reserved() 12. Get_Handle_Count() 13. Get_Handle_pages() 14. Get_All_Handle_Pages() 15. Get_Set_Page_Map() 16. Get_Set_Partial_Page_Map() 17. Map_Unmap_Multiple_Handle_Pages() 18. Reallocate_Pages() 19. Get_Set_Handle_Attribute() 20. Get_Set_Handle_Name() 21. Get_Handle_Directory() 22. Alter_Page_Map_And_Jump() 23. Alter_Page_Map_And_Call() 24. Move_Exchange_Memory_Region() 25. Get_Mappable_Physical_Address_Array() 26. Get_Hardware_Configuration_Array() 27. Allocate_Raw_Pages() 28. Alternate_Map_Register_Support() 29. Prepare_Expanded_Memory_HW_For_Warm_Boot() 30. Enable_Disable_OSE_Function_Set_Functions() 31. reset_emm_funcs() ========================================================================= AMMENDMENTS : ========================================================================= */ #ifdef LIM #ifdef SEGMENTATION /* * The following #include specifies the code segment into which this * module will by placed by the MPW C compiler on the Mac II running * MultiFinder. */ #include "SOFTPC_LIM.seg" #endif #include #include TypesH #include #include TimeH #include "xt.h" #include "sas.h" #include CpuH #include "emm.h" #if defined(SUN_VA) || defined(NTVDM) #include "error.h" #include "config.h" #endif /* SUN or NTVDM */ #include "timeval.h" #include "debug.h" #ifndef PROD #include "trace.h" #endif #include "timer.h" #include #include "gisp_sas.h" /* Global Variables */ #ifdef SCCSID static char SccsID[]="@(#)emm_funcs.c 1.27 2/22/94 Copyright Insignia Solutions Ltd."; #endif /* Forward Declarations */ /* External Declarations */ IMPORT void dma_lim_setup IPT0(); IMPORT void host_get_access_key IPT1(unsigned short *, access_key); #if defined(A2CPU) && defined(DELTA) IMPORT void reset_delta_data_structures IPT0(); #endif /* A2CPU && DELTA */ /* Local Variables */ static short map_on_return[MAX_NO_PAGES]; /* list of pages to be */ /* mapped on return from func 23*/ static unsigned short segment68, /* segment address of BOP 0x68 */ offset68; /* offset address of BOP 0x68 */ static boolean disabled = FALSE; /* flag used to disable funcs. */ /* 26, 28 and 30 */ static unsigned short alt_map_segment, /* segment address of map array */ alt_map_offset; /* offset of map array */ /* in function 28 */ #ifndef NTVDM static boolean set_called; /* flag to indicate if the 'set'*/ /* sub-function has been called */ /* in function 28 */ #endif #ifndef PROD static FILE *fp; static boolean trace_flag = FALSE; #endif /* Internal Function Declarations */ LOCAL void Get_Status(); LOCAL void Get_Page_Frame_Address(); LOCAL void Get_Unallocated_Page_Count(); LOCAL void Allocate_Pages(); LOCAL void Map_Unmap_Handle_Pages(); LOCAL void Deallocate_Pages(); LOCAL void Get_Version(); LOCAL void Save_Page_Map(); LOCAL void Restore_Page_Map(); LOCAL void Reserved(); LOCAL void Get_Handle_Count(); LOCAL void Get_Handle_Pages(); LOCAL void Get_All_Handle_Pages(); LOCAL void Get_Set_Page_Map(); LOCAL void Get_Set_Partial_Page_Map(); LOCAL void Map_Unmap_Multiple_Handle_Pages(); LOCAL void Reallocate_Pages(); LOCAL void Get_Set_Handle_Attribute(); LOCAL void Get_Set_Handle_Name(); LOCAL void Get_Handle_Directory(); LOCAL void Alter_Page_Map_And_Jump(); LOCAL void Alter_Page_Map_And_Call(); LOCAL void Move_Exchange_Memory_Region(); LOCAL void Get_Mappable_Physical_Address_Array(); LOCAL void Get_Hardware_Configuration_Array(); LOCAL void Allocate_Raw_Pages(); LOCAL void Alternate_Map_Register_Support(); LOCAL void Prepare_Expanded_Memory_HW_For_Warm_Boot(); LOCAL void Enable_Disable_OSE_Function_Set_Functions(); LOCAL void Increment_Address IPT4(unsigned short *,seg_or_page, unsigned short *,offset, unsigned long, increment_by, unsigned char, memory_type); #ifndef PROD LOCAL void Start_Trace(); LOCAL void End_Trace(); #endif void (*emm_func[]) () = { Get_Status, Get_Page_Frame_Address, Get_Unallocated_Page_Count, Allocate_Pages, Map_Unmap_Handle_Pages, Deallocate_Pages, Get_Version, Save_Page_Map, Restore_Page_Map, Reserved, Reserved, Get_Handle_Count, Get_Handle_Pages, Get_All_Handle_Pages, Get_Set_Page_Map, Get_Set_Partial_Page_Map, Map_Unmap_Multiple_Handle_Pages, Reallocate_Pages, Get_Set_Handle_Attribute, Get_Set_Handle_Name, Get_Handle_Directory, Alter_Page_Map_And_Jump, Alter_Page_Map_And_Call, Move_Exchange_Memory_Region, Get_Mappable_Physical_Address_Array, Get_Hardware_Configuration_Array, Allocate_Raw_Pages, Alternate_Map_Register_Support, Prepare_Expanded_Memory_HW_For_Warm_Boot, Enable_Disable_OSE_Function_Set_Functions #ifndef PROD ,Start_Trace, End_Trace #endif }; #ifndef PROD char *func_names[] = { "Get_Status", "Get_Page_Frame_Address", "Get_Unallocated_Page_Count", "Allocate_Pages", "Map_Unmap_Handle_Pages", "Deallocate_Pages", "Get_Version", "Save_Page_Map", "Restore_Page_Map", "Reserved", "Reserved", "Get_Handle_Count", "Get_Handle_Pages", "Get_All_Handle_Pages", "Get_Set_Page_Map", "Get_Set_Partial_Page_Map", "Map_Unmap_Multiple_Handle_Pages", "Reallocate_Pages", "Get_Set_Handle_Attribute", "Get_Set_Handle_Name", "Get_Handle_Directory", "Alter_Page_Map_And_Jump", "Alter_Page_Map_And_Call", "Move_Exchange_Memory_Region", "Get_Mappable_Physical_Address_Array", "Get_Hardware_Configuration_Array", "Allocate_Raw_Pages", "Alternate_Map_Register_Support", "Prepare_Expanded_Memory_HW_For_Warm_Boot", "Enable_Disable_OSE_Function_Set_Functions" #ifndef PROD ,"Start_Trace", "End_Trace" #endif }; #endif /* Defintion of this is non-standard */ #ifndef min #define min(a,b) (((a)<(b)) ? (a) : (b)) #endif /* =========================================================================== FUNCTION : emm_io PURPOSE : This is THE top level call to the EMM RETURNED STATUS : none DESCRIPTION : uses a function jump table to call the appropriate routine for each EMM function. The type of function is encoded into the AH register ========================================================================= */ GLOBAL void emm_io IFN0() { int func_num; if(getAH() >= MIN_FUNC_NO && getAH() <= MAX_FUNC_NO) { func_num = getAH() - MIN_FUNC_NO; sure_note_trace5(LIM_VERBOSE, "func %s - AX %#x BX %#x CX %#x DX %#x ", func_names[func_num],getAX(),getBX(),getCX(),getDX()); #ifdef EMM_DEBUG printf("emm_io entry: func=%s, AX=%x, BX=%x, CX=%x, DX=%x\n", func_names[func_num],getAX(),getBX(),getCX(),getDX() ); #endif (*emm_func[func_num])(); #ifdef EMM_DEBUG printf("emm_io exit: AX=%x, BX=%x, CX=%x, DX=%x\n", getAX(),getBX(),getCX(),getDX() ); #endif if (getAH() != SUCCESS) { sure_note_trace5(LIM_VERBOSE, "func %s failed - AX %#x BX %#x CX %#x DX %#x\n", func_names[func_num],getAX(),getBX(),getCX(),getDX()); } else { sure_note_trace5(LIM_VERBOSE, "func %s succeeded - AX %#x BX %#x CX %#x DX %#x\n", func_names[func_num],getAX(),getBX(),getCX(),getDX()); } } else { sure_note_trace1(LIM_VERBOSE,"Bad LIM call %#x\n", getAH()); setAH(BAD_FUNC_CODE); } } #ifdef SEGMENTATION /* * The following #include specifies the code segment into which this * module will by placed by the MPW C compiler on the Mac II running * MultiFinder. */ #include "SOFTPC_INIT.seg" #endif /* =========================================================================== FUNCTION : emm_init PURPOSE : This routine is called from the driver to pass back the address of the bop 68 (return_from_call) call and to find out how many pages have been installed RETURNED STATUS : none DESCRIPTION : DS:DX contains the segment:offset of the bop68 call the number of pages is returned in BX ========================================================================= */ GLOBAL void emm_init IFN0() { short total_pages; #ifdef GISP_SVGA /* * Check whether LIM is possible. If it isn't (because the page * frame's already been used for the ROMs) * warn the user, and bail out. */ if (LimBufferInUse()) { host_error(EG_NO_ROOM_FOR_LIM, ERR_CONT | ERR_QUIT, ""); setBX((word)0); /* return error to driver */ return; } #endif /* GISP_SVGA */ #ifdef SUN_VA half_word emm_all[256]; half_word *cptr; half_word temp; int i; int found_mb = FALSE; #endif #if defined(SUN_VA) || defined(NTVDM) SHORT limSize, backFill; #endif segment68 = getDS(); offset68 = getDX(); #ifdef SUN_VA /* * config.sys command line pointer is passed in the DI:DX registers from the driver. */ ea = effective_addr(getDI(), getCX()); i = 0; do{ sas_load(ea + i, &temp); emm_all[i] = temp; if (temp == '/'){ found_mb = TRUE; cptr = &emm_all[i+1]; /* point to digit after flag */ } i++; } while ( (temp != NULL) && (temp != NL) && (temp != CR)); emm_all[i-1] = NULL; /* In cased it is not NULL */ /* * Search for #MB of EMM requested */ if ((found_mb == TRUE) && isdigit(*cptr) ) { temp = atoi(cptr); } else { /* EMM size not specified */ temp = 2; /* default to 2MB */ } /* * Initialise the LIM * */ if (limSize = (SHORT)config_inquire(C_LIM_SIZE, NULL)){ backFill = 640; /* We will always have at least 640k */ limSize--; /* Subtract 1M of regular DOS memory */ /* * Check that we have enough raw memory for the EMM request. * If not, set to the available memory size. */ if ( temp <= limSize) limSize = temp; while (init_expanded_memory(limSize, backFill) != SUCCESS ) { free_expanded_memory(); host_error(EG_EXPANDED_MEM_FAILURE, ERR_QU_CO, NULL); } } #endif /* SUN_VA */ #ifdef NTVDM /* Similar to SUN_VA but without command line sizing */ if ((limSize = (SHORT)config_inquire(C_LIM_SIZE, NULL)) && get_no_phys_pages()) { backFill = 640; if (init_expanded_memory(limSize, backFill) == FAILURE) { if (get_total_pages() == (short)0xffff) /* config error */ { setBX((word)0xffff); /* return error to driver */ return; } else { /* out of memory */ setBX((word)0); /* return error to driver */ return; } } } #endif /* NTVDM */ total_pages = get_total_pages(); setBX(total_pages); /* Let the rest of SoftPC know that Expanded Memory is present * and active */ if( total_pages ) { dma_lim_setup(); #if defined(A2CPU) && defined(DELTA) reset_delta_data_structures(); #endif /* A2CPU && DELTA */ } return; } #ifdef SEGMENTATION /* * The following #include specifies the code segment into which this * module will by placed by the MPW C compiler on the Mac II running * MultiFinder. */ #include "SOFTPC_LIM.seg" #endif /* =========================================================================== FUNCTION : Get_Status PURPOSE : Returns the status indicating whether the memory manager has been initialised successfuly RETURNED STATUS : in AH register SUCCESS - everything OK EMM_HW_ERROR - memory manager not initialised successfuly DESCRIPTION : checks the number of pages available ========================================================================= */ LOCAL void Get_Status IFN0() { if(get_total_pages() == 0) setAH(EMM_HW_ERROR); else setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Get_Page_Frame_Address PURPOSE : Returns the segment address where the page frame is located RETURNED STATUS : in AH register SUCCESS - Allocation successful DESCRIPTION : ========================================================================= */ LOCAL void Get_Page_Frame_Address IFN0() { setBX(get_base_address()); setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Get_Unallocated_Page_Count PURPOSE : Returns the number of unallocated (available) expanded memory pages and the total number of pages RETURNED STATUS : in AH register SUCCESS - Allocation successful DESCRIPTION : ========================================================================= */ LOCAL void Get_Unallocated_Page_Count IFN0() { setBX(get_unallocated_pages()); setDX(get_total_pages()); setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Allocate_Pages PURPOSE : Allocates a number of Expanded Memory Pages to the next available handle number RETURNED STATUS : in AH register SUCCESS - Allocation successful NOT_ENOUGH_PAGES - not enough pages in the system NO_MORE_PAGES - not enough free pages available NO_MORE_HANDLES - no more free handles available EMM_HW_ERROR - memory allocation error DESCRIPTION : ========================================================================= */ LOCAL void Allocate_Pages IFN0() { short handle_no, no_of_pages, /* no of pages to be allocated */ i, /* loop counter */ EM_page_no; /* Expanded Memory page number */ no_of_pages = getBX(); if(get_total_open_handles() >= get_total_handles()) { setAH(NO_MORE_HANDLES); return; } if(no_of_pages > get_total_pages()) { setAH(NOT_ENOUGH_PAGES); return; } if(no_of_pages > get_unallocated_pages()) { setAH(NO_MORE_PAGES); return; } if((handle_no = get_new_handle(no_of_pages)) == FAILURE) { setAH(EMM_HW_ERROR); return; } set_no_pages(handle_no, no_of_pages); for(i=0; i= get_no_phys_pages()) { setAH(BAD_PHYS_PAGE); return; } no_of_pages = get_no_pages(handle_no); if((logical_page_no < -1) || (logical_page_no >= no_of_pages)) { setAH(BAD_LOG_PAGE); return; } /* * If you get to here, all parameters must be ok - so start mapping */ if(logical_page_no == -1) { /* * Unmapping required */ if(unmap_page(physical_page_no) != SUCCESS) { setAH(EMM_HW_ERROR); return; } } else { /* * Mapping required */ EM_page_no = get_EMpage_no(handle_no, logical_page_no); if(map_page(EM_page_no, physical_page_no) != SUCCESS) { setAH(EMM_HW_ERROR); return; } } setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Deallocate_Pages PURPOSE : Deallocates all pages assigned to the specified handle number, freeing them for further use, also frees the handle number itself. RETURNED STATUS : in AH register SUCCESS - Deallocation successful BAD_HANDLE - couldn't find specified handle MAP_SAVED - there is a map context saved in this handle EMM_HW_ERROR - unable to free page or memory DESCRIPTION : ========================================================================= */ LOCAL void Deallocate_Pages IFN0() { short handle_no, no_of_pages, /* no of pages in handle */ i, /* loop counter */ EM_page_no; /* Expanded Memory page number */ handle_no = getDX(); if (!handle_ok(handle_no)) { setAH(BAD_HANDLE); return; } if(map_saved(handle_no)) { setAH(MAP_SAVED); return; } /* * Free pages */ no_of_pages = get_no_pages(handle_no); for(i = 0; i < no_of_pages; i++) { EM_page_no = get_EMpage_no(handle_no, i); if (free_page(EM_page_no) != SUCCESS) { setAH(EMM_HW_ERROR); return; } } /* * free handle */ if (handle_no != 0) /* reserved handle no */ if (free_handle(handle_no) != SUCCESS) { setAH(EMM_HW_ERROR); return; } setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Get Version PURPOSE : Returns the version number of the memory manager software RETURNED STATUS : in AH register SUCCESS - returned successfuly DESCRIPTION : ========================================================================= */ LOCAL void Get_Version IFN0() { setAL(VERSION); setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Save_Page_Map PURPOSE : Saves the contents of the page mapping registers RETURNED STATUS : in AH register SUCCESS - Mapping context saved successfuly BAD_HANDLE - couldn't find specified handle MAP_IN_USE - mapping already saved for this handle DESCRIPTION : ========================================================================= */ LOCAL void Save_Page_Map IFN0() { short handle_no; handle_no = getDX(); if(!handle_ok(handle_no)) { setAH(BAD_HANDLE); return; } if(map_saved(handle_no)) { setAH(MAP_IN_USE); return; } save_map(handle_no, 0, 0, 0, 0); setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Restore_Page_Map PURPOSE : restores the mapping context associated with a particular handle This function only restores the map for the 4 physical pages that existed in LIM 3. RETURNED STATUS : in AH register SUCCESS - mapping restored successfuly BAD_HANDLE - couldn't find specified handle NO_MAP - No map has been saved for this handle EMM_HW_ERROR - error occurred in mapping or unmapping DESCRIPTION : ========================================================================= */ LOCAL void Restore_Page_Map IFN0() { short handle_no, pages_out[MAX_NO_PAGES], /* pages to map out */ pages_in[MAX_NO_PAGES], /* pages to map in */ i; /* loop counter */ handle_no = getDX(); if(!handle_ok(handle_no)) { setAH(BAD_HANDLE); return; } if(!map_saved(handle_no)) { setAH(NO_MAP); return; } restore_map(handle_no, 0, 0, pages_out, pages_in); for(i = 0; i < 4; i++) /* Only do the 4 pages supported by EMS 3 !! */ { if(pages_out[i] != EMPTY) if(unmap_page(i) != SUCCESS) { setAH(EMM_HW_ERROR); return; } if(pages_in[i] != EMPTY) if(map_page(pages_in[i], i) != SUCCESS) { setAH(EMM_HW_ERROR); return; } } setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : PURPOSE : RETURNED STATUS : in AH register SUCCESS - DESCRIPTION : ========================================================================= */ LOCAL void Reserved IFN0() { setAH(BAD_FUNC_CODE); return; } /* =========================================================================== FUNCTION : Get_Handle_Count PURPOSE : Returns the number of open EMM handles RETURNED STATUS : in AH register SUCCESS - number returned successfuly DESCRIPTION : ========================================================================= */ LOCAL void Get_Handle_Count IFN0() { setBX(get_total_open_handles()); setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Get_Handle_Pages PURPOSE : returns the number of pages assigned to a particular handle RETURNED STATUS : in AH register SUCCESS - Page count returned successfuly BAD_HANDLE - couldn't find specified handle DESCRIPTION : ========================================================================= */ LOCAL void Get_Handle_Pages IFN0() { short handle_no; handle_no = getDX(); if (!handle_ok(handle_no)) { setAH(BAD_HANDLE); return; } setBX(get_no_pages(handle_no)); setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Get_All_Handle_Pages PURPOSE : Returns a list of all open handles and the number of pages assigned to each handle RETURNED STATUS : in AH register SUCCESS - Everything ok DESCRIPTION : ========================================================================= */ LOCAL void Get_All_Handle_Pages IFN0() { unsigned short segment, /* segment address of position */ /* to return data to */ offset; /* offset within segment */ short no_of_handles, /* no. of open handles */ no_of_pages, /* no of pages in each handle */ i, /* Loop counter */ handle_no; segment = getES(); offset = getDI(); no_of_handles = get_total_open_handles(); handle_no = 0; for (i = 0; i < no_of_handles; i++) { while(!handle_ok(handle_no)) handle_no++; no_of_pages = get_no_pages(handle_no); write_intel_word(segment, offset, handle_no); offset += 2; write_intel_word(segment, offset, no_of_pages); offset += 2; handle_no++; } setBX(no_of_handles); setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Get_Set_Page_Map PURPOSE : saves mapping context in a user supplied array and restores a previously saved context from a given array RETURNED STATUS : in AH register SUCCESS - Everything ok BAD_SUB_FUNC - Invalid sub-function BAD_MAP - The contents of the map are a load of cak DESCRIPTION : ========================================================================= */ LOCAL void Get_Set_Page_Map IFN0() { unsigned short src_segment, /* segment address of src array */ src_offset, /* offset of source array */ dst_segment, /* segment address of dst array */ dst_offset; /* offset of destination array */ unsigned char sub_func; /* sub-function code */ short pages_out[MAX_NO_PAGES],/* pages to map out */ pages_in[MAX_NO_PAGES], /* pages to map in */ no_phys_pages, /* no. of phys. pages available */ i; /* loop counter */ sub_func = getAL(); switch(sub_func) { case 0: case 2: dst_segment = getES(); dst_offset = getDI(); save_map(-1, dst_segment, dst_offset, 0, 0); if(sub_func == 0 ) break; case 1: src_segment = getDS(); src_offset = getSI(); if(restore_map(-1 , src_segment, src_offset, pages_out, pages_in) != SUCCESS) { setAH(BAD_MAP); return; } no_phys_pages = get_no_phys_pages(); for(i = 0; i < no_phys_pages; i++) { if(pages_out[i] != EMPTY) if(unmap_page(i) != SUCCESS) { setAH(EMM_HW_ERROR); return; } if(pages_in[i] != EMPTY) if(map_page(pages_in[i], i) != SUCCESS) { setAH(EMM_HW_ERROR); return; } } break; case 3: setAL((unsigned char)get_map_size()); break; default: setAH(BAD_SUB_FUNC); return; } setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Get_Set_Partial_Page_map PURPOSE : Only saves or restores part of a complete page map as specified by a user supplied array RETURNED STATUS : in AH register SUCCESS - Everything ok BAD_SEGMENT - one of the specified segments is incorrect BAD_SUB_FUNC - Invalid sub-function BAD_MAP - The contents of the map are a load of cak DESCRIPTION : Note in this implementation the size of array used for storing the partial mapping context is the same as for storing a full context as the pages that are'nt specified are marked in the array as being empty ========================================================================= */ LOCAL void Get_Set_Partial_Page_Map IFN0() { unsigned short src_segment, /* segment address of src array */ src_offset, /* offset of source array */ dst_segment, /* segment address of dst array */ dst_offset; /* offset of destination array */ unsigned char sub_func; /* sub-function code */ short pages_out[MAX_NO_PAGES],/* pages to map out */ pages_in[MAX_NO_PAGES], /* pages to map in */ no_phys_pages, /* no. of phys. pages available */ i; /* loop counter */ sub_func = getAL(); switch(sub_func) { case 0: dst_segment = getES(); dst_offset = getDI(); src_segment = getDS(); src_offset = getSI(); if(save_map(-2, dst_segment, dst_offset, src_segment, src_offset) != SUCCESS) { setAH(BAD_PHYS_PAGE); return; } break; case 1: src_segment = getDS(); src_offset = getSI(); if(restore_map(-1 , src_segment, src_offset, pages_out, pages_in) != SUCCESS) { setAH(BAD_MAP); return; } no_phys_pages = get_no_phys_pages(); for(i = 0; i < no_phys_pages; i++) { if(pages_out[i] != EMPTY) if(unmap_page(i) != SUCCESS) { setAH(EMM_HW_ERROR); return; } if(pages_in[i] != EMPTY) if(map_page(pages_in[i], i) != SUCCESS) { setAH(EMM_HW_ERROR); return; } } break; case 2: setAL((unsigned char)get_map_size()); break; default: setAH(BAD_SUB_FUNC); return; } setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Map_Unmap_Multiple_Handle_Pages PURPOSE : maps and umaps the requested Expanded Memory pages into and out of Intel physical address space RETURNED STATUS : in AH register SUCCESS - Mapping/Unmapping successful BAD_HANDLE - couldn't find specified handle BAD_LOG_PAGE - invalid logical page number BAD_PHYS_PAGE - invalid physical page number BAD_SUB_FUNC - invalid sub-function code EMM_HW_ERROR - unable to map/unmap for some unspecified reason DESCRIPTION : ========================================================================= */ LOCAL void Map_Unmap_Multiple_Handle_Pages IFN0() { unsigned short segment, /* segment address of map array */ offset, /* offset address of map array */ value; /* segment address or page no. */ short handle_no, logical_page_no, /* page no. within handle */ EM_page_no, /* Expanded memory page */ no_of_pages, /* No. of pages in handle */ no_phys_pages, /* no. of phys. pages available */ pages_to_map, /* total no of pages to map */ i; /* loop counter */ unsigned char sub_func, /* sub-function code */ physical_page_no; sub_func = getAL(); if(sub_func > 1) { setAH(BAD_SUB_FUNC); return; } handle_no = getDX(); if(!handle_ok(handle_no)) { setAH(BAD_HANDLE); return; } no_of_pages = get_no_pages(handle_no); pages_to_map = getCX(); segment = getDS(); offset = getSI(); for(i = 0; i < pages_to_map; i++) { read_intel_word(segment, offset, (word *)&logical_page_no); offset += 2; read_intel_word(segment, offset, &value); offset += 2; no_phys_pages = get_no_phys_pages(); if(sub_func == 1) { physical_page_no = 0; do if(value == get_page_seg(physical_page_no)) break; while(++physical_page_no < no_phys_pages); } else physical_page_no = (unsigned char)value; if(physical_page_no >= no_phys_pages) { setAH(BAD_PHYS_PAGE); return; } if((logical_page_no < -1) || (logical_page_no >= no_of_pages)) { setAH(BAD_LOG_PAGE); return; } /* * If you get to here, all parameters must be ok - so start mapping */ if(logical_page_no == -1) { /* * Unmapping required */ if(unmap_page(physical_page_no) != SUCCESS) { setAH(EMM_HW_ERROR); return; } } else { /* * Mapping required */ EM_page_no = get_EMpage_no(handle_no, logical_page_no); if(map_page(EM_page_no, physical_page_no) != SUCCESS) { setAH(EMM_HW_ERROR); return; } } } setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Reallocate_Pages PURPOSE : Changes the number of pages assigned to a handle RETURNED STATUS : in AH register SUCCESS - Everything ok BAD_HANDLE - invalid handle number NOT_ENOUGH_PAGES - Not enough pages in the system NO_MORE_PAGES - not enough free pages available EMM_HW_ERROR - memory allocation error DESCRIPTION : ========================================================================= */ LOCAL void Reallocate_Pages IFN0() { short handle_no, EM_page_no, /* Expanded Memory page number */ old_page_count, /* no. of pages in handle */ new_page_count, /* required pages in handle */ i; /* loop counter */ handle_no = getDX(); if(!handle_ok(handle_no)) { setAH(BAD_HANDLE); return; } new_page_count = getBX(); if(new_page_count > get_total_pages()) { setAH(NOT_ENOUGH_PAGES); return; } old_page_count = get_no_pages(handle_no); if((new_page_count - old_page_count) > get_unallocated_pages()) { setAH(NO_MORE_PAGES); return; } if(new_page_count > old_page_count) { if(reallocate_handle(handle_no, old_page_count, new_page_count) != SUCCESS) { setAH(EMM_HW_ERROR); return; } set_no_pages(handle_no, new_page_count); for(i = old_page_count; i < new_page_count; i++) { if((EM_page_no = alloc_page()) < SUCCESS) { setAH(EMM_HW_ERROR); return; } set_EMpage_no(handle_no, i, EM_page_no); } } else if(new_page_count < old_page_count) { set_no_pages(handle_no, new_page_count); for(i = new_page_count; i < old_page_count; i++) { EM_page_no = get_EMpage_no(handle_no, i); if(free_page(EM_page_no) != SUCCESS) { setAH(EMM_HW_ERROR); return; } } } setBX(new_page_count); setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Get_Set_Handle_Attribute PURPOSE : RETURNED STATUS : in AH register SUCCESS - everything ok (Al set to 0 also) NOT_SUPPORTED - this function not supported BAD_SUB_FUNC - invalid sub_function DESCRIPTION : Non - volatile handles are currently not supported ========================================================================= */ LOCAL void Get_Set_Handle_Attribute IFN0() { unsigned char sub_func; /* sub_function code */ sub_func = getAL(); if(sub_func > 2) { setAH(BAD_SUB_FUNC); return; } if(sub_func < 2) { setAH(NOT_SUPPORTED); return; } /* * Setting AL to 0 here indicates support of volatile handles only */ setAL(0); setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Get_Set_Handle_Name PURPOSE : Assigns or retrieves a name to or from a given handle RETURNED STATUS : in AH register SUCCESS - Everything ok BAD_HANDLE - Invalid handle BAD_SUB_FUNC -Invalid sub-function code NAME_EXISTS - Name already exists in another handle DESCRIPTION : ========================================================================= */ LOCAL void Get_Set_Handle_Name IFN0() { unsigned char sub_func; /* sub-function code */ short handle_no, no_of_handles, /* no of open(allocated) handles*/ tmp_hndl_no, /* temp. variable for handle no */ i; /* loop counter */ unsigned short segment, /* segment address of name */ offset; /* offset address of name */ char name[NAME_LENGTH], /* array for holding name */ *name_ptr; /* pointer to existing names */ sub_func = getAL(); if(sub_func > 1) { setAH(BAD_SUB_FUNC); return; } handle_no = getDX(); if(!handle_ok(handle_no)) { setAH(BAD_HANDLE); return; } if(sub_func == 0) { segment = getES(); offset = getDI(); name_ptr = get_name(handle_no); write_intel_byte_string(segment, offset, (host_addr)name_ptr, NAME_LENGTH); } else if(sub_func == 1) { segment = getDS(); offset = getSI(); read_intel_byte_string(segment, offset, (host_addr)name, NAME_LENGTH); /* * check all existing names */ no_of_handles = get_total_open_handles(); tmp_hndl_no = 0; for(i = 0; i < no_of_handles; i++) { while(!handle_ok(tmp_hndl_no)) tmp_hndl_no++; name_ptr = get_name(tmp_hndl_no); if(strncmp(name, name_ptr, NAME_LENGTH) == 0) { setAH(NAME_EXISTS); return; } tmp_hndl_no++; } /* * If you get here - name must be ok */ set_name(handle_no, name); } setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Get_Handle_Directory PURPOSE : Returns a list of handles and their names RETURNED STATUS : in AH register SUCCESS - Everything ok BAD_SUB_FUNC - Invalid sub-function HANDLE_NOT_FOUND - could not find handle with specified name DESCRIPTION : ========================================================================= */ LOCAL void Get_Handle_Directory IFN0() { unsigned char sub_func; /* sub-function code */ unsigned short segment, /* segment address of name array*/ offset; /* offset of name array */ short handle_no, no_of_handles, /* no. of open handles */ i; /* loop counter */ char *name_ptr, /* pointer to name */ name[NAME_LENGTH]; /* name to search for */ sub_func = getAL(); switch(sub_func) { case 0: segment = getES(); offset = getDI(); no_of_handles = get_total_open_handles(); handle_no = 0; for(i = 0; i < no_of_handles; i++) { while(!handle_ok(handle_no)) handle_no++; name_ptr = get_name(handle_no); write_intel_word(segment, offset, handle_no); offset += 2; write_intel_byte_string(segment, offset, (host_addr)name_ptr, NAME_LENGTH); offset += NAME_LENGTH; handle_no++; } setAL((unsigned char)no_of_handles); break; case 1: segment = getDS(); offset = getSI(); read_intel_byte_string(segment, offset, (host_addr)name, NAME_LENGTH); no_of_handles = get_total_open_handles(); handle_no = 0; for(i = 0; i < no_of_handles; i++) { while(!handle_ok(handle_no)) handle_no++; name_ptr = get_name(handle_no); if(strncmp(name, name_ptr, NAME_LENGTH) == 0) break; handle_no++; } if(i >= no_of_handles) { setAH(HANDLE_NOT_FOUND); return; } setDX(handle_no); break; case 2: setBX(get_total_handles()); break; default: setAH(BAD_SUB_FUNC); return; } setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Alter_Page_Map_And_Jump PURPOSE : Map a selection of pages and jump to a new address RETURNED STATUS : in AH register SUCCESS - Everything ok BAD_HANDLE - Couldn't find specified handle BAD_SUB_FUNC - Invalid sub-function code BAD_LOG_PAGE - Invalid logical page number BAD_PHYS_PAGE - Invalid physical page number EMM_HW_ERROR - Unable to map or unmap for some undefined reason DESCRIPTION : ========================================================================= */ LOCAL void Alter_Page_Map_And_Jump IFN0() { short handle_no, no_of_pages, /* pages assigned to handle */ no_phys_pages, /* no. of phys. pages available */ EM_page_no, /* Expanded memory page no. */ i; /* Loop counter */ unsigned short segment, /* segment of data structure */ offset, /* offset of data structure */ jmp_segment, /* segment of address to jump to*/ jmp_offset, /* offset of address to jump to */ map_segment, /* segment of mapping data */ map_offset, /* offset of mapping data */ logical_page_no,/* number of logical page */ value; /* segment/page no. (AL=0 or 1) */ unsigned char sub_func, /* sub-function code */ pages_to_map, /* no of pages to be mapped in */ physical_page_no; /* number of physical page */ handle_no = getDX(); if(!handle_ok(handle_no)) { setAH(BAD_HANDLE); return; } sub_func = getAL(); if(sub_func > 1) { setAH(BAD_SUB_FUNC); return; } segment = getDS(); offset = getSI(); read_intel_word(segment, offset, &jmp_offset); offset += 2; read_intel_word(segment, offset, &jmp_segment); offset += 2; read_intel_byte(segment, offset, &pages_to_map); offset++; read_intel_word(segment, offset, &map_offset); offset += 2; read_intel_word(segment, offset, &map_segment); offset += 2; no_of_pages = get_no_pages(handle_no); for(i = 0; i < pages_to_map; i++) { read_intel_word(map_segment, map_offset, &logical_page_no); map_offset += 2; if(logical_page_no >= no_of_pages) { setAH(BAD_LOG_PAGE); return; } read_intel_word(map_segment, map_offset, &value); map_offset += 2; no_phys_pages = get_no_phys_pages(); if(sub_func == 1) { physical_page_no = 0; do if(value == get_page_seg(physical_page_no)) break; while(++physical_page_no < no_phys_pages); } else physical_page_no = (unsigned char)value; if(physical_page_no >= no_phys_pages) { setAH(BAD_PHYS_PAGE); return; } EM_page_no = get_EMpage_no(handle_no, logical_page_no); if(map_page(EM_page_no, physical_page_no) != SUCCESS) { setAH(EMM_HW_ERROR); return; } } /* * Push flags and segment:offset of target address onto stack * to enable iret in driver to transfer control */ push_word((word)getSTATUS()); push_word(jmp_segment); push_word(jmp_offset); setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Alter_Page_Map_And_Call return_from_call PURPOSE : Map a selection of pages and transfer control to a new address. Upon return map in a different set of pages RETURNED STATUS : in AH register SUCCESS - Everything ok BAD_HANDLE - Couldn't find specified handle BAD_SUB_FUNC - Invalid sub-function code BAD_LOG_PAGE - Invalid logical page number BAD_PHYS_PAGE - Invalid physical page number EMM_HW_ERROR - Unable to map or unmap for some undefined reason DESCRIPTION : The return is handled by loading the segment and offset of the BOP 0x68 call onto the stack. This BOP will initiate a call to 'return_from_call()' which will handle the remapping. ========================================================================= */ LOCAL void Alter_Page_Map_And_Call IFN0() { short handle_no, no_of_pages, /* pages assigned to handle */ no_phys_pages, /* no. of phys. pages available */ EM_page_no, /* Expanded memory page no. */ i; /* Loop counter */ unsigned short segment, /* segment of data structure */ offset, /* offset of data structure */ call_segment, /* segment of address to jump to*/ call_offset, /* offset of address to jump to */ map_segment, /* segment of mapping data */ map_offset, /* offset of mapping data */ logical_page_no,/* number of logical page */ value; /* segment/page no. (AL=0 or 1) */ unsigned char sub_func, /* sub-function code */ pages_to_map, /* no of pages to be mapped in */ physical_page_no; /* number of physical page */ sub_func = getAL(); if(sub_func > 2) { setAH(BAD_SUB_FUNC); return; } if(sub_func != 2) { handle_no = getDX(); if(!handle_ok(handle_no)) { setAH(BAD_HANDLE); return; } segment = getDS(); offset = getSI(); read_intel_word(segment, offset, &call_offset); offset += 2; read_intel_word(segment, offset, &call_segment); offset += 2; read_intel_byte(segment, offset, &pages_to_map); offset++; read_intel_word(segment, offset, &map_offset); offset += 2; read_intel_word(segment, offset, &map_segment); offset += 2; no_of_pages = get_no_pages(handle_no); for(i = 0; i < pages_to_map; i++) { read_intel_word(map_segment, map_offset, &logical_page_no); map_offset += 2; if(logical_page_no >= no_of_pages) { setAH(BAD_LOG_PAGE); return; } read_intel_word(map_segment, map_offset, &value); map_offset += 2; no_phys_pages = get_no_phys_pages(); if(sub_func == 1) { physical_page_no = 0; do if(value == get_page_seg(physical_page_no)) break; while(++physical_page_no < no_phys_pages); } else physical_page_no = (unsigned char)value; if(physical_page_no >= no_phys_pages) { setAH(BAD_PHYS_PAGE); return; } EM_page_no = get_EMpage_no(handle_no, logical_page_no); if(map_page(EM_page_no, physical_page_no) != SUCCESS) { setAH(EMM_HW_ERROR); return; } } /* * Now set up mapping data for return * read new segment, offset and pages to map data */ read_intel_byte(segment, offset, &pages_to_map); offset++; read_intel_word(segment, offset, &map_offset); offset += 2; read_intel_word(segment, offset, &map_segment); offset += 2; for(i = 0; i < no_phys_pages; map_on_return[i++] = EMPTY); for(i = 0; i < pages_to_map; i++) { read_intel_word(map_segment, map_offset, &logical_page_no); map_offset += 2; if(logical_page_no >= no_of_pages) { setAH(BAD_LOG_PAGE); return; } read_intel_word(map_segment, map_offset, &value); map_offset += 2; if(sub_func == 1) { physical_page_no = 0; do if(value == get_page_seg(physical_page_no)) break; while(++physical_page_no < no_phys_pages); } else physical_page_no = (unsigned char)value; if(physical_page_no >= no_phys_pages) { setAH(BAD_PHYS_PAGE); return; } EM_page_no = get_EMpage_no(handle_no, logical_page_no); map_on_return[physical_page_no] = EM_page_no; } /* * Push segment:offset of bop68 onto stack to trap far return */ push_word(segment68); push_word(offset68); /* * Push flags and segment:offset of target address onto stack * to enable iret in driver to transfer control */ push_word((word)getSTATUS()); push_word(call_segment); push_word(call_offset); } else /* if sub_func == 2 */ setBX(10); setAH(SUCCESS); return; } GLOBAL void return_from_call IFN0() { unsigned char page_no; /* physical page number */ short no_phys_pages; /* no. of phys. pages available */ no_phys_pages = get_no_phys_pages(); for(page_no = 0; page_no < no_phys_pages; page_no++) { if(map_on_return[page_no] != EMPTY) if(map_page(map_on_return[page_no], page_no) != SUCCESS) { setAH(EMM_HW_ERROR); return; } } setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Move_Exchange_Memory_Region PURPOSE : copies a region of memory from either, conventional or expanded memory to either, conventional or expanded memory. RETURNED STATUS : in AH register SUCCESS - Everything ok BAD_SUB_FUNC - Invalid sub-function code BAD_HANDLE - couldn't find specified handle BAD_LOG_PAGE - invalid logical page number MOVE_MEM_OVERLAP - Source and destination regions overlap during move XCHG_MEM_OVERLAP - Source and destination regions overlap during exchange TOO_FEW_PAGES - Insufficient pages in handle for operation OFFSET_TOO_BIG - Offsey exceeds size of page LENGTH_GT_1M - Memory length to be moved exceeds 1 M byte BAD_TYPE - Unsupported memory type WRAP_OVER_1M - Attempt made to wrap around the 1 Mbyte address EMM_HW_ERROR - Undefined error occurred during copying DESCRIPTION : type - uses a bit pattern, bit 0 represents destination, bit 1 represents source, a set bit means expanded, a clear bit means conventional memory bit 2 represents exchange if set or move if it is clear e.g. 0 (0000) = move conventional to conventional 1 (0001) = move conventional to expanded 6 (0110) = exchange expanded to conventional 7 (0111) = exchange expanded to expanded ========================================================================= */ LOCAL void Move_Exchange_Memory_Region IFN0() { unsigned char sub_func, /* sub-function code */ type, /* see description above */ mem_type; /* type of src or dest memory */ unsigned short segment, /* segment address of structure */ offset, /* offset address of structure */ half_length, /* tmp store for reading length */ src_offset, /* offset of source memory */ src_seg_page, /* segment or page of src memory*/ dst_offset, /* offset of destination memory */ dst_seg_page; /* segment or page of dst memory*/ unsigned long length, /* length of memory region */ src_start, /* start of src within handle */ src_end, /* end of src within handle */ dst_start, /* start of dest within handle */ dst_end, /* end of dest within handle */ data_block_size,/* transfer data block size */ bytes_available;/* no. bytes to end of handle */ short src_handle_no, /* source handle number */ dst_handle_no, /* dest handle number */ no_of_pages; /* no. of pages within handle */ boolean overlap; /* indicates a memory overlap */ sub_func = getAL(); if(sub_func > 1) { setAH(BAD_SUB_FUNC); return; } type = sub_func << 2; segment = getDS(); offset = getSI(); read_intel_word(segment, offset, &half_length); offset += 2; length = half_length; read_intel_word(segment, offset, &half_length); offset += 2; length += (((long)half_length) << 16); if(length > 0x100000) { setAH(LENGTH_GT_1M); return; } /* * READ SOURCE DATA */ read_intel_byte(segment, offset, &mem_type); offset++; if(mem_type > 1) { setAH(BAD_TYPE); return; } type |= (mem_type << 1); read_intel_word(segment, offset, (word *)&src_handle_no); offset += 2; if(mem_type == 1) { if(!handle_ok(src_handle_no)) { setAH(BAD_HANDLE); return; } } read_intel_word(segment, offset, &src_offset); offset += 2; read_intel_word(segment, offset, &src_seg_page); offset += 2; if(mem_type == 1) { no_of_pages = get_no_pages(src_handle_no); if(src_seg_page >= no_of_pages) { setAH(BAD_LOG_PAGE); return; } if(src_offset >= EMM_PAGE_SIZE) { setAH(OFFSET_TOO_BIG); return; } bytes_available = ((no_of_pages - src_seg_page + 1) * EMM_PAGE_SIZE) - src_offset; if(length > bytes_available) { setAH(TOO_FEW_PAGES); return; } } else { if((effective_addr(src_seg_page, src_offset) + length) >= 0x100000) { setAH(WRAP_OVER_1M); return; } } /* * READ DESTINATION DATA */ read_intel_byte(segment, offset, &mem_type); offset++; if(mem_type > 1) { setAH(BAD_TYPE); return; } type |= mem_type; read_intel_word(segment, offset, (word *)&dst_handle_no); offset += 2; if(mem_type == 1) { if(!handle_ok(dst_handle_no)) { setAH(BAD_HANDLE); return; } } read_intel_word(segment, offset, &dst_offset); offset += 2; read_intel_word(segment, offset, &dst_seg_page); offset += 2; if(mem_type == 1) { no_of_pages = get_no_pages(dst_handle_no); if(dst_seg_page >= no_of_pages) { setAH(BAD_LOG_PAGE); return; } if(dst_offset >= EMM_PAGE_SIZE) { setAH(OFFSET_TOO_BIG); return; } bytes_available = ((no_of_pages - dst_seg_page + 1) * EMM_PAGE_SIZE) - dst_offset; if(length > bytes_available) { setAH(TOO_FEW_PAGES); return; } } else if(((((unsigned long)dst_seg_page) << 4) + dst_offset + length) >= 0x100000) { setAH(WRAP_OVER_1M); return; } /* * Check for overlap - ( only on expanded to expanded cases ) */ overlap = FALSE; if((type & 3) == 3) if(src_handle_no == dst_handle_no) { /* * calc start and end positions of src and dst * within handle */ src_start = (src_seg_page * EMM_PAGE_SIZE) + src_offset; src_end = src_start + length - 1; dst_start = (dst_seg_page * EMM_PAGE_SIZE) + dst_offset; dst_end = dst_start + length - 1; if((dst_start <= src_end && dst_start >= src_start) || (src_start <= dst_end && src_start >= dst_start)) { if(sub_func == 1) { setAH(XCHG_MEM_OVERLAP); return; } else overlap = TRUE; } } /* * If we get here everything is ok. Copy memory a page at a time, catering * for the fact that expanded memory pages might not be contiguous and may be * mapped into the intel address space. Remember that Intel memory may be * treated as contiguous memory. So an Intel address need only be incremented * if a copy spans more than one page of LIM memory. */ while (length>0) { int min_src, min_dst; min_src = (type & 2) ? min(EMM_PAGE_SIZE - src_offset, length) : length; min_dst = (type & 1) ? min(EMM_PAGE_SIZE - dst_offset, length) : length; data_block_size = min(min_src, min_dst); if(copy_exchange_data(type, src_handle_no, src_seg_page, src_offset, dst_handle_no, dst_seg_page, dst_offset, data_block_size) != SUCCESS) { setAH(EMM_HW_ERROR); return; } Increment_Address(&src_seg_page, &src_offset, data_block_size, (type & 2)); Increment_Address(&dst_seg_page, &dst_offset, data_block_size, (type & 1)); length -= data_block_size; } if(overlap) setAH(MOVE_MEM_OVERLAP); else setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Increment address PURPOSE : Increments an address, correctly catering for whether the address is an Intel (conventional memory) address or a LIM (expanded memory) address. RETURNED STATUS : None DESCRIPTION : ========================================================================= */ #define SEG_SIZE 0x10000 LOCAL void Increment_Address IFN4(unsigned short *,seg_or_page, unsigned short *,offset, unsigned long, increment_by, unsigned char, memory_type) { if (memory_type) { /* A LIM address, code makes assumption that increment across * page boundary will always be to page boundary. */ if (*offset + increment_by >= EMM_PAGE_SIZE) { (*seg_or_page)++; *offset = 0; } else { *offset += increment_by; } } else { /* Conventional memory */ if (*offset + increment_by >= SEG_SIZE) { unsigned long address; /* Make new segment value as high as possible, to * minimise chances of further segment wrap */ address = (*seg_or_page << 4) + *offset + increment_by; *seg_or_page = address >> 4; *offset = address & 0xf; } else { *offset += increment_by; } } } /* =========================================================================== FUNCTION : Get_Mappable_Physical_address_Array PURPOSE : returns an array of the sector address for each mappable page in physical address space RETURNED STATUS : in AH register SUCCESS - Everything ok BAD_SUB_FUNC - The sub function is invalid DESCRIPTION : ========================================================================= */ LOCAL void Get_Mappable_Physical_Address_Array IFN0() { unsigned short segment, /* segment address of position */ /* to return data to */ offset, /* offset within segment */ page_seg, /* segment address of page */ low_seg; /* lowest segment address */ short no_phys_pages; /* no. of phys. pages available */ unsigned char sub_func, /* sub-function */ page_no, /* physical page number */ lowest; /* page no. having lowest seg. */ sub_func = getAL(); no_phys_pages = get_no_phys_pages(); switch(sub_func) { case 0: segment = getES(); offset = getDI(); /* * must be written in address order - lowest first * if we are back filling page 0 is not the lowest */ lowest = 0; low_seg = get_page_seg(0); for(page_no = 1; page_no < no_phys_pages; page_no++) if((page_seg = get_page_seg(page_no)) < low_seg) { lowest = page_no; low_seg = page_seg; } for(page_no = lowest; page_no < no_phys_pages; page_no++) { page_seg = get_page_seg(page_no); write_intel_word(segment, offset, page_seg); offset += 2; write_intel_word(segment, offset, (short)page_no); offset += 2; } for(page_no = 0; page_no < lowest; page_no++) { page_seg = get_page_seg(page_no); write_intel_word(segment, offset, page_seg); offset += 2; write_intel_word(segment, offset, (short)page_no); offset += 2; } case 1: break; default: setAH(BAD_SUB_FUNC); return; } setCX(no_phys_pages); setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Get_Expanded_Memory_Hardware_Information PURPOSE : Returns an array containing hardware configuration information RETURNED STATUS : in AH register SUCCESS - Everything ok BAD_SUB_FUNC - invalid sub-function ACCESS_DENIED - the OS has denied access to this function DESCRIPTION : ========================================================================= */ LOCAL void Get_Hardware_Configuration_Array IFN0() { unsigned short segment, /* segment address of position */ /* to return data to */ offset; /* offset within segment */ short sub_func, /* sub-function */ unallocated_raw_pages, total_raw_pages, context_save_area_size; sub_func = getAL(); switch(sub_func) { case 0: if(disabled) { setAH(ACCESS_DENIED); return; } segment = getES(); offset = getDI(); context_save_area_size = get_map_size(); write_intel_word(segment, offset, RAW_PAGE_SIZE); offset += 2; #ifdef NTVDM write_intel_word(segment, offset, get_no_altreg_sets()); #else write_intel_word(segment, offset, ALT_REGISTER_SETS); #endif offset += 2; write_intel_word(segment, offset, context_save_area_size); offset += 2; write_intel_word(segment, offset, DMA_CHANNELS); offset += 2; write_intel_word(segment, offset, DMA_CHANNEL_OPERATION); break; /* * Our raw pages are the same size as the std pages */ case 1: unallocated_raw_pages = get_unallocated_pages(); total_raw_pages = get_total_pages(); setBX(unallocated_raw_pages); setDX(total_raw_pages); break; default: setAH(BAD_SUB_FUNC); return; } setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Allocate_Raw_Pages PURPOSE : Allocates the requested number of raw pages, in this case our Raw pages are exactly the same as conventional pages. RETURNED STATUS : in AH register SUCCESS - Allocation successful NOT_ENOUGH_PAGES - not enough pages in the system NO_MORE_PAGES - not enough free pages available NO_MORE_HANDLES - no more free handles available EMM_HW_ERROR - memory allocation error BAD_FUNC_CODE - invalid function code DESCRIPTION : ========================================================================= */ LOCAL void Allocate_Raw_Pages IFN0() { short handle_no, no_of_pages, /* no of pages to be allocated */ i, /* loop counter */ EM_page_no; /* Expanded Memory page number */ no_of_pages = getBX(); if(no_of_pages > get_total_pages()) { setAH(NOT_ENOUGH_PAGES); return; } if(no_of_pages > get_unallocated_pages()) { setAH(NO_MORE_PAGES); return; } if((handle_no = get_new_handle(no_of_pages)) < SUCCESS) { setAH(EMM_HW_ERROR); return; } set_no_pages(handle_no, no_of_pages); for(i=0; i= get_no_altreg_sets()){ setAH(UNSUPPORTED_ALT_REGS); break; } else if (!altreg_set_ok(map_register)) { setAH(INVALID_ALT_REG); break; } pages_in_override = FALSE; if (map_register == 0) { alt_map_segment = getES(); alt_map_offset = getDI(); if (alt_map_segment && alt_map_offset) { no_phys_pages = get_no_phys_pages(); offset = alt_map_offset; for (i = 0; i < no_phys_pages; i++) { sas_loadw(effective_addr(alt_map_segment, offset), &pages_in[i]); offset += sizeof(word); } pages_in_override = TRUE; } } if (activate_altreg_set(map_register, (pages_in_override) ? pages_in : NULL )) setAH(EMM_SUCCESS); else setAH(EMM_HW_ERROR); break; case 2: setDX(get_map_size()); break; case 3: if (allocate_altreg_set(&map_register)) { setBL(map_register); setAH(EMM_SUCCESS); } else { setBL(0); setAH(NO_FREE_ALT_REGS); } break; case 4: map_register = getBL(); /* immediately retrun okay if trying to deallocate alt reg 0 */ if (map_register == 0) setAH(EMM_SUCCESS); else if (map_register == get_active_altreg_set()) if (get_no_altreg_sets() == 1) setAH(NO_ALT_REGS); else setAH(INVALID_ALT_REG); else if(deallocate_altreg_set(map_register)) setAH(EMM_SUCCESS); else setAH(EMM_HW_ERROR); break; case 5: case 6: case 7: case 8: map_register = getBL(); if(map_register != 0) { setAH(NO_ALT_REGS); return; } break; default: setAH(BAD_SUB_FUNC); return; } setAH(SUCCESS); return; #else unsigned char sub_func, /* sub-function code */ map_register; /* No. of alternate register */ short pages_out[MAX_NO_PAGES],/* pages to map out */ pages_in[MAX_NO_PAGES], /* pages to map in */ no_phys_pages, /* no. of phys. pages available */ i; /* loop counter */ if(disabled) { setAH(ACCESS_DENIED); return; } sub_func = getAL(); switch(sub_func) { case 0: if(set_called) save_map(-1, alt_map_segment, alt_map_offset, 0, 0); setES(alt_map_segment); setDI(alt_map_offset); break; case 1: set_called = TRUE; map_register = getBL(); if(map_register != 0) { setAH(NO_ALT_REGS); return; } alt_map_segment = getES(); alt_map_offset = getDI(); /* * Undocumented feature (???) to restore the * alternative mappings back to their original * state a NULL ptr is passed into here (ES:DI == 0) * We must therefore set things as if set_alt had * never been called */ if ((alt_map_segment == 0) && (alt_map_offset == 0)) { set_called = FALSE; break; } if(restore_map(-1 , alt_map_segment, alt_map_offset, pages_out, pages_in) != SUCCESS) { setAH(BAD_MAP); return; } no_phys_pages = get_no_phys_pages(); for(i = 0; i < no_phys_pages; i++) { if(pages_out[i] != EMPTY) if(unmap_page(i) != SUCCESS) { setAH(EMM_HW_ERROR); return; } if(pages_in[i] != EMPTY) if(map_page(pages_in[i], i) != SUCCESS) { setAH(EMM_HW_ERROR); return; } } break; case 2: setDX(get_map_size()); break; case 3: case 5: setBL(0); break; case 4: case 6: case 7: case 8: map_register = getBL(); if(map_register != 0) { setAH(NO_ALT_REGS); return; } break; default: setAH(BAD_SUB_FUNC); return; } setAH(SUCCESS); return; #endif } /* =========================================================================== FUNCTION : Prepare_Expanded_Memory_HW_For_Warm_Boot PURPOSE : RETURNED STATUS : in AH register SUCCESS - DESCRIPTION : We don't actually do anything here, we just pretend that we do ========================================================================= */ LOCAL void Prepare_Expanded_Memory_HW_For_Warm_Boot IFN0() { setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : Enable_Disable_OSE_Function_Set_Functions PURPOSE : Enables or disables the functions:- Get Expanded Memory Hardware Information, Alternate Map Register Sets Enable Disable OS/E Function Set Functions RETURNED STATUS : in AH register SUCCESS - Everything OK BAD_SUB_FUNC - invalid sub-function code ACCESS_DENIED - the OS has denied access to this function DESCRIPTION : ========================================================================= */ LOCAL void Enable_Disable_OSE_Function_Set_Functions IFN0() { static unsigned short access_key[2]; /* random access key in BX & CX */ static boolean first_time = TRUE; /* first time through flag */ unsigned char sub_func; /* sub-function code */ if(!first_time) { /* * We must check the 'access key' */ if((access_key[0] != getBX()) || (access_key[1] != getCX())) { setAH(ACCESS_DENIED); return; } } sub_func = getAL(); switch(sub_func) { case 0: if(first_time) { host_get_access_key(access_key); setBX(access_key[0]); setCX(access_key[1]); first_time = FALSE; } disabled = FALSE; break; case 1: if(first_time) { host_get_access_key(access_key); setBX(access_key[0]); setCX(access_key[1]); first_time = FALSE; } disabled = TRUE; break; case 2: disabled = FALSE; first_time = TRUE; break; default: setAH(BAD_SUB_FUNC); return; } setAH(SUCCESS); return; } /* =========================================================================== FUNCTION : reset_emm_funcs PURPOSE : sets up variables to their initial value, used mainly for SoftPC reboot RETURNED STATUS : none DESCRIPTION : ========================================================================= */ GLOBAL void reset_emm_funcs IFN0() { /* * These variables are used in function 28 * (Alternate Map Register Support) */ alt_map_segment = 0; alt_map_offset = 0; #ifndef NTVDM set_called = FALSE; #endif return; } #ifndef PROD /* =========================================================================== FUNCTION : Routines to start and end a trace of all EMM calls PURPOSE : RETURNED STATUS : in AH register SUCCESS DESCRIPTION : ========================================================================= */ LOCAL void Start_Trace IFN0() { if ((fp = fopen("emm_trace","w")) == NULL) { setAH(EMM_HW_ERROR); return; } setbuf(fp, NULL); trace_flag = TRUE; setAH(SUCCESS); return; } LOCAL void End_Trace IFN0() { fflush(fp); fclose(fp); trace_flag = FALSE; setAH(SUCCESS); return; } #endif /* PROD */ #endif /* LIM */