mirror of https://github.com/lianthony/NT4.0
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.
2833 lines
63 KiB
2833 lines
63 KiB
#include "insignia.h"
|
|
#include "host_def.h"
|
|
|
|
#ifdef SUN_VA
|
|
#define MAXPATHLEN 1024
|
|
#define NL 0x0a
|
|
#define CR 0x0d
|
|
#include <ctype.h>
|
|
#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 <stdio.h>
|
|
#include TypesH
|
|
#include <string.h>
|
|
#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 <error.h>
|
|
#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<no_of_pages; i++)
|
|
{
|
|
if ((EM_page_no = alloc_page()) == FAILURE)
|
|
{
|
|
setAH(EMM_HW_ERROR);
|
|
return;
|
|
}
|
|
set_EMpage_no(handle_no, i, EM_page_no);
|
|
}
|
|
|
|
setDX(handle_no);
|
|
setAH(SUCCESS);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : Map_Unmap_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
|
|
EMM_HW_ERROR - unable to map/unmap for some unspecified
|
|
reason
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
LOCAL void Map_Unmap_Handle_Pages IFN0()
|
|
{
|
|
short handle_no,
|
|
logical_page_no, /* page no. within handle */
|
|
EM_page_no, /* Expanded memory page */
|
|
no_of_pages; /* No. of pages in handle */
|
|
unsigned char
|
|
physical_page_no; /* page no. in Intel physical */
|
|
/* address space */
|
|
|
|
handle_no = getDX();
|
|
physical_page_no = getAL();
|
|
logical_page_no = getBX();
|
|
|
|
if(!handle_ok(handle_no))
|
|
{
|
|
setAH(BAD_HANDLE);
|
|
return;
|
|
}
|
|
if(physical_page_no >= 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<no_of_pages; i++)
|
|
{
|
|
if ((EM_page_no = alloc_page()) < SUCCESS)
|
|
{
|
|
setAH(EMM_HW_ERROR);
|
|
return;
|
|
}
|
|
set_EMpage_no(handle_no, i, EM_page_no);
|
|
}
|
|
|
|
setDX(handle_no);
|
|
setAH(SUCCESS);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : Alternate_Map_Register_Support();
|
|
|
|
PURPOSE : provides an alternate method of saving and restoring
|
|
mapping contexts
|
|
|
|
RETURNED STATUS : in AH register
|
|
SUCCESS - Everything OK
|
|
NO_ALT_REGS - Alternate Map register sets not supported
|
|
BAD_MAP - Contents of the map are invalid
|
|
BAD_SUB_FUNC - invalid sub-function code
|
|
ACCESS_DENIED - the OS has denied access to this function
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
LOCAL void Alternate_Map_Register_Support IFN0()
|
|
{
|
|
|
|
#ifdef NTVDM
|
|
|
|
unsigned char sub_func; /* sub-function code */
|
|
|
|
short
|
|
pages_in[MAX_NO_PAGES], /* pages to map in */
|
|
no_phys_pages, /* no. of phys. pages available */
|
|
i; /* loop counter */
|
|
unsigned short offset, map_register;
|
|
boolean pages_in_override;
|
|
|
|
if(disabled)
|
|
{
|
|
setAH(ACCESS_DENIED);
|
|
return;
|
|
}
|
|
|
|
sub_func = getAL();
|
|
switch(sub_func) {
|
|
|
|
case 0:
|
|
map_register = get_active_altreg_set();
|
|
if (map_register == 0) {
|
|
setES(alt_map_segment);
|
|
setDI(alt_map_offset);
|
|
if (alt_map_segment && alt_map_offset)
|
|
save_map(-1, alt_map_segment, alt_map_offset, 0, 0);
|
|
}
|
|
setBL(map_register);
|
|
setAH(EMM_SUCCESS);
|
|
break;
|
|
|
|
case 1:
|
|
map_register = getBL();
|
|
if (map_register >= 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 */
|