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.
2129 lines
50 KiB
2129 lines
50 KiB
#include "insignia.h"
|
|
#include "host_def.h"
|
|
/* INSIGNIA MODULE SPECIFICATION
|
|
-----------------------------
|
|
SccsID : @(#)emm_mngr.c 1.24 08/31/93 Copyright Insignia Solutions Ltd.
|
|
FILE NAME : emm_mngr.c
|
|
MODULE NAME : 'Middle 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 : April '88
|
|
|
|
PURPOSE : Contains all the routines that communicate with
|
|
the arrays and data structures that hold the
|
|
necessary Expanded Memory Manager Data.
|
|
|
|
|
|
The Following Routines are defined:
|
|
1. init_expanded_memory()
|
|
2. free_expanded_memory()
|
|
3. get_new_handle()
|
|
4. free_handle()
|
|
5. reallocate_handle()
|
|
6. handle_ok()
|
|
7. set_no_pages()
|
|
8. set_EM_pageno()
|
|
9. set_map()
|
|
10. set_name()
|
|
11. get_no_pages()
|
|
12. get_EM_pageno()
|
|
13. get_map()
|
|
14. get_name()
|
|
15. alloc_page()
|
|
16. free_page()
|
|
17. map_page()
|
|
18. unmap_page()
|
|
19. map_saved()
|
|
20. save_map()
|
|
21. restore_map()
|
|
22. copy_exchange_data()
|
|
23. page_status()
|
|
The following routines just return variables to the top layer
|
|
24. get_total_pages()
|
|
25. get_unallocated_pages()
|
|
26. get_base_address()
|
|
27. get_total_handles()
|
|
28. get_total_open_handles()
|
|
29. get_no_phys_pages()
|
|
30. get_page_seg()
|
|
31. get_map_size()
|
|
|
|
=========================================================================
|
|
|
|
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 <string.h>
|
|
|
|
#if defined(NTVDM) && defined(MONITOR)
|
|
#include <malloc.h>
|
|
#endif
|
|
|
|
#include TypesH
|
|
|
|
#include "xt.h"
|
|
#include CpuH
|
|
#include "sas.h"
|
|
#include "host_emm.h"
|
|
#include "emm.h"
|
|
#include "gmi.h"
|
|
#include "debug.h"
|
|
#ifndef PROD
|
|
#include "trace.h"
|
|
#endif
|
|
#include "timer.h"
|
|
|
|
#ifdef NTVDM
|
|
#include "error.h"
|
|
#endif /* NTVDM */
|
|
|
|
typedef enum
|
|
{
|
|
BYTE_OP,
|
|
WORD_OP,
|
|
STR_OP
|
|
} MM_LIM_op_type;
|
|
|
|
#ifdef NTVDM
|
|
/* Local Variables */
|
|
static long
|
|
handle[MAX_NO_HANDLES], /* Array containing unique ID's */
|
|
/* for each handle, these are */
|
|
/* usually pointers, but this */
|
|
/* is host dependant */
|
|
backfill; /* backfill memory size */
|
|
static unsigned short
|
|
total_pages = 0, /* no. of EM pages available */
|
|
unallocated_pages = 0, /* no. of unallocated EM pages */
|
|
total_handles, /* no of handles available */
|
|
total_open_handles, /* no. of allocated handles */
|
|
*EM_page_mapped_array = NULL, /* EMM page mapped array */
|
|
*EM_page_mapped = NULL, /* Expanded Memory pages */
|
|
/* currently mapped in */
|
|
page_offset, /* offset in handle data at */
|
|
/* which page numbers start */
|
|
map_size, /* no of bytes rq'd to store map*/
|
|
no_phys_pages = 0, /* no. of phys. pages available */
|
|
no_altreg_sets = 0; /* no of alternative reg sets */
|
|
static unsigned short
|
|
physical_page[MAX_NO_PAGES]; /* array containing segment */
|
|
/* addresses of physical pages */
|
|
|
|
static unsigned short
|
|
EM_start, EM_end;
|
|
static IU8
|
|
* altreg_alloc_mask; /* altref allocate mask */
|
|
static unsigned short
|
|
next_free_altreg_set, /* next free altreg set #, 0 based */
|
|
free_altreg_sets, /* number of free altreg */
|
|
active_altreg_set = 0; /* current active alt reg set */
|
|
static char
|
|
name[NAME_LENGTH]; /* for storing handle name */
|
|
|
|
#define GET_EM_PAGE_MAPPED_PTR(set) (EM_page_mapped_array + \
|
|
(set * no_phys_pages))
|
|
|
|
/* get emm parameters, initialize housekeeping structures and
|
|
* reserve page frames.
|
|
*/
|
|
|
|
boolean lim_page_frame_init(PLIM_CONFIG_DATA lim_config_data)
|
|
{
|
|
int i;
|
|
unsigned short altreg_alloc_mask_size; /* altreg allocation mask array size */
|
|
|
|
no_phys_pages = get_lim_page_frames(physical_page, lim_config_data);
|
|
|
|
/* The first 4 pages must be continuous and locate above 640KB
|
|
* (the EMM primary page frame(physical pages 0, 1, 2 and 3)).
|
|
* It is then followed by other pages located above 640KB and then
|
|
* pages below 640KB(back fill)
|
|
*/
|
|
if (!no_phys_pages)
|
|
return FALSE;
|
|
|
|
no_altreg_sets = lim_config_data->total_altreg_sets;
|
|
backfill = lim_config_data->backfill;
|
|
|
|
|
|
/* each mapping register set has no_phys_pages pages */
|
|
EM_page_mapped_array = host_malloc(no_phys_pages * no_altreg_sets *
|
|
sizeof(short));
|
|
if (EM_page_mapped_array == NULL) {
|
|
host_error(EG_MALLOC_FAILURE, ERR_CONT, "");
|
|
return FALSE;
|
|
}
|
|
/* one bit for each altreg set */
|
|
altreg_alloc_mask_size = (no_altreg_sets + 7) / 8;
|
|
altreg_alloc_mask = host_malloc(altreg_alloc_mask_size);
|
|
if (altreg_alloc_mask == NULL) {
|
|
host_free(EM_page_mapped_array);
|
|
host_error(EG_MALLOC_FAILURE, ERR_CONT, "");
|
|
return FALSE;
|
|
}
|
|
|
|
/* all altreg sets are free at this moment */
|
|
for (i = 0; i < altreg_alloc_mask_size; i++)
|
|
altreg_alloc_mask[i] = 0;
|
|
|
|
next_free_altreg_set = 0;
|
|
free_altreg_sets = no_altreg_sets;
|
|
return TRUE;
|
|
}
|
|
#else
|
|
|
|
|
|
/* Local Variables */
|
|
static long
|
|
#ifdef macintosh
|
|
*handle;
|
|
#else
|
|
handle[MAX_NO_HANDLES]; /* Array containing unique ID's */
|
|
/* for each handle, these are */
|
|
/* usually pointers, but this */
|
|
/* is host dependant */
|
|
#endif /* !macintosh */
|
|
|
|
static short
|
|
total_pages = 0, /* no. of EM pages available */
|
|
unallocated_pages = 0, /* no. of unallocated EM pages */
|
|
total_handles, /* no of handles available */
|
|
total_open_handles, /* no. of allocated handles */
|
|
EM_page_mapped[MAX_NO_PAGES], /* Expanded Memory pages */
|
|
/* currently mapped in */
|
|
page_offset, /* offset in handle data at */
|
|
/* which page numbers start */
|
|
map_size, /* no of bytes rq'd to store map*/
|
|
no_phys_pages; /* no. of phys. pages available */
|
|
|
|
static unsigned int
|
|
EM_start, /* start segment for EM mapping */
|
|
EM_end; /* 1st segment past end of EM */
|
|
|
|
static unsigned short
|
|
physical_page[MAX_NO_PAGES]; /* array containing segment */
|
|
/* addresses of physical pages */
|
|
|
|
static char
|
|
name[NAME_LENGTH]; /* for storing handle name */
|
|
|
|
#endif
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : init_expanded_memory
|
|
|
|
PURPOSE : This routine calls the routine to allocate the expanded
|
|
memory pages and then sets up the arrays and variables that
|
|
are used by the Expanded Memory Manager(EMM).
|
|
|
|
RETURNED STATUS : SUCCESS - manager initialised succesfully
|
|
FAILURE - Failure to allocate space for Expanded Memory
|
|
pages.
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL int init_expanded_memory IFN2(int, size, /* size of area in megabytes */
|
|
int, mem_limit /* limit of conventional memory
|
|
* 256, 512 or 640KB */ )
|
|
|
|
{
|
|
short
|
|
pages_above_640, /* no of mappable locations */
|
|
pages_below_640, /* available either side of 640*/
|
|
EM_page_no, /* page no. within exp. memory */
|
|
physical_page_no; /* page no. within map region */
|
|
unsigned short
|
|
base; /* start segment of mappable */
|
|
/* memory below 640 KB */
|
|
|
|
int i, j; /* loop counters */
|
|
|
|
|
|
if (!no_phys_pages)
|
|
return FAILURE;
|
|
|
|
/* get space for expanded memory pages */
|
|
|
|
if(host_initialise_EM(size) != SUCCESS)
|
|
{
|
|
#ifdef NTVDM
|
|
host_error(EG_EXPANDED_MEM_FAILURE, ERR_QU_CO, NULL);
|
|
#endif /* NTVDM */
|
|
return(FAILURE);
|
|
}
|
|
|
|
#ifdef macintosh
|
|
if (!handle)
|
|
{
|
|
handle = (long *)host_malloc(MAX_NO_HANDLES*sizeof(long));
|
|
}
|
|
#endif /* macintosh */
|
|
|
|
/* Initialise EMM variables */
|
|
|
|
#ifndef NTVDM
|
|
EM_start = 0xd000;
|
|
EM_end = 0xe000;
|
|
#else
|
|
EM_start = physical_page[0];
|
|
EM_end = physical_page[0] + EMM_PAGE_SIZE * 4;
|
|
#endif
|
|
total_pages = unallocated_pages = size * 0x100000 / EMM_PAGE_SIZE;
|
|
|
|
/* always allow max handles (Used to be 32 handles/Meg expanded mem) */
|
|
total_handles = MAX_NO_HANDLES;
|
|
total_open_handles = 0;
|
|
for(i = 0; i < total_handles; i++)
|
|
handle[i] = (long) NULL;
|
|
|
|
#ifdef NTVDM
|
|
map_size = no_phys_pages * NSIZE;
|
|
page_offset = MAP_OFFSET + map_size;
|
|
pages_below_640 = backfill / EMM_PAGE_SIZE;
|
|
pages_above_640 = no_phys_pages - pages_below_640;
|
|
|
|
/* initialize active mapping register to set 0 */
|
|
EM_page_mapped = EM_page_mapped_array;
|
|
allocate_altreg_set(&active_altreg_set);
|
|
|
|
for (i = 0; i < no_phys_pages; i++)
|
|
EM_page_mapped[i] = (unsigned short)EMPTY;
|
|
|
|
if (get_new_handle(0) != 0)
|
|
return FAILURE;
|
|
set_no_pages(0, 0);
|
|
#else
|
|
|
|
pages_above_640 = (effective_addr(EM_end,0) - effective_addr(EM_start,0)) / EMM_PAGE_SIZE;
|
|
pages_below_640 = ((640 - mem_limit) * 1024) / EMM_PAGE_SIZE;
|
|
no_phys_pages = pages_above_640 + pages_below_640;
|
|
|
|
map_size = no_phys_pages * NSIZE;
|
|
page_offset = MAP_OFFSET + map_size;
|
|
|
|
/*
|
|
* set up addresses and mapping status of physical pages
|
|
*/
|
|
for( i = 0; i < pages_above_640; i++ )
|
|
{
|
|
physical_page[i] = EM_start + (i * EMM_PAGE_SIZE >> 4);
|
|
EM_page_mapped[i] = EMPTY;
|
|
}
|
|
base = mem_limit * 64;
|
|
|
|
for(i = pages_above_640, j = 0; i < no_phys_pages; i++)
|
|
{
|
|
physical_page[i] = base + (j++ * EMM_PAGE_SIZE >> 4);
|
|
EM_page_mapped[i] = EMPTY;
|
|
}
|
|
/*
|
|
* Allocate handle 0 with any pages required for back filling
|
|
*/
|
|
if(get_new_handle(pages_below_640) != 0)
|
|
return(FAILURE);
|
|
|
|
for(i = 0, physical_page_no = pages_above_640; i < pages_below_640; i++)
|
|
{
|
|
if((EM_page_no = alloc_page()) == FAILURE)
|
|
return (FAILURE);
|
|
|
|
set_EMpage_no(0, i, EM_page_no);
|
|
|
|
if(map_page(EM_page_no, physical_page_no++) == FAILURE)
|
|
return(FAILURE);
|
|
}
|
|
set_no_pages(0, pages_below_640);
|
|
#endif /* NTVDM */
|
|
|
|
/*
|
|
* Set up necessary variables in Top level EMM function code
|
|
*/
|
|
reset_emm_funcs();
|
|
|
|
/*
|
|
** Map the address space taken up by LIM to RAM.
|
|
** Without LIM it would be ROM.
|
|
** The range seems to be fixed at segment D000 to F000.
|
|
** Assumed that AT's have GMI and XT's do not.
|
|
** XT's can use the old fashioned memset calls in
|
|
** delta:manager:init_struc.c
|
|
*/
|
|
#ifdef NTVDM
|
|
/* every physical page must be connected as RAM */
|
|
for (i = 0; i < pages_above_640; i++)
|
|
sas_connect_memory(effective_addr(physical_page[i], 0),
|
|
effective_addr(physical_page[i], EMM_PAGE_SIZE - 1),
|
|
SAS_RAM
|
|
);
|
|
#else
|
|
|
|
sas_connect_memory(effective_addr(EM_start,0) , effective_addr(EM_end,0) -1 , SAS_RAM );
|
|
#endif
|
|
|
|
sure_note_trace3(LIM_VERBOSE,"initialised EMM, total pages= %#x, pages above 640= %#x, pages below 640 = %#x",no_phys_pages, pages_above_640, pages_below_640);
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : free_expanded_memory
|
|
|
|
PURPOSE : This routine calls frees all memory allocated for the
|
|
expanded memory manager and resets the variables that
|
|
are used by the Expanded Memory Manager(EMM).
|
|
|
|
RETURNED STATUS : SUCCESS -
|
|
|
|
DESCRIPTION : If total_pages = 0, this indicates that expanded
|
|
memory hasn't been initialised, so the routine simply
|
|
does nothing and returns.
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL void free_expanded_memory IFN0()
|
|
|
|
{
|
|
short handle_no;
|
|
|
|
if(total_pages == 0)
|
|
return;
|
|
|
|
/* free space allocated for each handle */
|
|
|
|
handle_no = 0;
|
|
while(total_open_handles > 0)
|
|
{
|
|
while(!handle_ok(handle_no))
|
|
handle_no++;
|
|
|
|
free_handle(handle_no++);
|
|
}
|
|
/*
|
|
* Free space for expanded memory pages
|
|
*/
|
|
host_deinitialise_EM();
|
|
|
|
total_pages = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : get_new_handle()
|
|
|
|
PURPOSE : Finds the next free handle no., allocates storage space
|
|
for recording the EMM data associated with this handle,
|
|
and stores the 'storage ID' in the handle array.
|
|
|
|
RETURNED STATUS : SUCCESS - new handle allocated successfully
|
|
FAILURE - Error occurred in trying to allocate storage
|
|
space for handle data
|
|
|
|
DESCRIPTION : see emm.h for a description of space required for
|
|
storing handle data e.g. PAGE_OFFSET & NSIZE
|
|
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL short get_new_handle IFN1(short, no_pages) /* No.of pages to store in handle */
|
|
|
|
{
|
|
short i; /* loop count */
|
|
short handle_no;
|
|
int data_size; /* no. of bytes of data storage */
|
|
long storage_ID; /* host dependant storage */
|
|
/* identifier, usually a ptr. */
|
|
|
|
sure_note_trace2(LIM_VERBOSE,"new handle request, current total handles= %d, pages requested = %d",total_handles, no_pages);
|
|
|
|
handle_no = 0;
|
|
|
|
do
|
|
if (handle[handle_no] == (long) NULL)
|
|
break;
|
|
while(++handle_no < total_handles);
|
|
|
|
if(handle_no >= total_handles)
|
|
return(FAILURE);
|
|
|
|
data_size = page_offset + (no_pages * NSIZE);
|
|
|
|
if ((storage_ID = host_allocate_storage(data_size)) == (long) NULL)
|
|
return(FAILURE);
|
|
|
|
handle[handle_no] = storage_ID;
|
|
|
|
for (i=0 ; i < no_phys_pages ; i++) {
|
|
set_map_no(handle_no, i, FREE);
|
|
}
|
|
|
|
total_open_handles++;
|
|
|
|
sure_note_trace1(LIM_VERBOSE,"allocation OK, return handle=%d",handle_no);
|
|
|
|
return(handle_no);
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : free_handle
|
|
|
|
PURPOSE : frees the storage space allocated to the handle number.
|
|
Decrements the handles open count
|
|
|
|
RETURNED STATUS : SUCCESS - space freed
|
|
FAILURE - unable to free space
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL int free_handle IFN1(short, handle_no) /* No.of handle to be freed */
|
|
|
|
{
|
|
long storage_ID; /* host dependant storage */
|
|
/* identifier, usually a ptr. */
|
|
|
|
sure_note_trace2(LIM_VERBOSE, "free handle %d request, total handles = %d",handle_no, total_handles);
|
|
|
|
storage_ID = handle[handle_no];
|
|
|
|
if(host_free_storage(storage_ID) != SUCCESS)
|
|
return(FAILURE);
|
|
|
|
handle[handle_no] = (long) NULL;
|
|
|
|
total_open_handles--;
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : reallocate_handle
|
|
|
|
PURPOSE : changes the number of pages allocated to a given handle
|
|
|
|
RETURNED STATUS : SUCCESS - handle reallocated
|
|
FAILURE - unable to get space for new handle data
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL int reallocate_handle IFN3(short, handle_no, /* handle to be reallocated */
|
|
short, old_page_count,/* current pages in handle */
|
|
short, new_page_count)/* required pages for handle*/
|
|
|
|
{
|
|
long storage_ID; /* host dependant storage */
|
|
/* identifier, usually a ptr. */
|
|
|
|
short size, /* size of handle data area */
|
|
new_size; /* size of new handle data area */
|
|
|
|
|
|
size = page_offset + (old_page_count * NSIZE);
|
|
new_size = page_offset + (new_page_count * NSIZE);
|
|
storage_ID = handle[handle_no];
|
|
|
|
sure_note_trace3(LIM_VERBOSE,"reallocate pages for handle %d, old size=%#x, new size= %#x",handle_no, size, new_size);
|
|
|
|
if((storage_ID = host_reallocate_storage(storage_ID, size, new_size)) ==
|
|
(long) NULL)
|
|
return(FAILURE);
|
|
|
|
handle[handle_no] = storage_ID;
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : handle_ok
|
|
|
|
PURPOSE : checks to see if the handle no. is valid - this should
|
|
be called before every routine that uses a handle number
|
|
to retrieve or set data in the handle data area
|
|
|
|
RETURNED STATUS : TRUE - Handle no. is valid
|
|
FALSE - Handle no. is invalid
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL boolean handle_ok IFN1(short, handle_no)
|
|
|
|
{
|
|
#ifdef NTVDM
|
|
/* some *** applicaitons feed us a negtive handle number. Catch it and
|
|
throw it to the hell*/
|
|
|
|
if ((unsigned short)handle_no >= (unsigned short)total_handles) {
|
|
#else
|
|
if(handle_no >= total_handles || handle_no < 0) {
|
|
#endif
|
|
|
|
sure_note_trace1(LIM_VERBOSE,"invalid handle %d",handle_no);
|
|
return(FALSE);
|
|
}
|
|
|
|
if(handle[handle_no] == (long) NULL){
|
|
sure_note_trace1(LIM_VERBOSE,"invalid handle %d",handle_no);
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : set_no_pages
|
|
|
|
PURPOSE : sets the no of pages variable in the specified handle
|
|
|
|
RETURNED STATUS :
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL void set_no_pages IFN2(short, handle_no, short, no_pages)
|
|
|
|
{
|
|
long storage_ID; /* host dependant storage */
|
|
/* identifier, usually a ptr. */
|
|
byte *ptr; /* pointer to storage area */
|
|
|
|
storage_ID = handle[handle_no];
|
|
ptr = USEBLOCK(storage_ID);
|
|
|
|
*(short *)ptr = no_pages;
|
|
|
|
FORGETBLOCK(storage_ID)
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : set_EMpage_no
|
|
|
|
PURPOSE : sets Expanded Memory page that is used for the specified
|
|
logical page into the handle data storage area
|
|
|
|
RETURNED STATUS :
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL void set_EMpage_no IFN3(short, handle_no,
|
|
short, logical_page_no,
|
|
short, EM_page_no)
|
|
|
|
{
|
|
long storage_ID; /* host dependant storage */
|
|
/* identifier, usually a ptr. */
|
|
byte *ptr; /* pointer to storage area */
|
|
|
|
storage_ID = handle[handle_no];
|
|
|
|
ptr = USEBLOCK(storage_ID);
|
|
/*
|
|
* offset pointer to correct position
|
|
*/
|
|
|
|
ptr += (page_offset +(logical_page_no * NSIZE));
|
|
*(short *)ptr = EM_page_no;
|
|
|
|
FORGETBLOCK(storage_ID)
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : set_map_no
|
|
|
|
PURPOSE : sets Expanded Memory page number in the map section of
|
|
the handle data storage area
|
|
|
|
RETURNED STATUS :
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL void set_map_no IFN3(short, handle_no,
|
|
unsigned char, physical_page_no,
|
|
short, EM_page_no)
|
|
|
|
{
|
|
long storage_ID; /* host dependant storage */
|
|
/* identifier, usually a ptr. */
|
|
unsigned char *ptr; /* pointer to storage area */
|
|
|
|
storage_ID = handle[handle_no];
|
|
|
|
ptr = USEBLOCK(storage_ID);
|
|
/*
|
|
* offset pointer to correct position
|
|
*/
|
|
|
|
ptr += (MAP_OFFSET +(physical_page_no * NSIZE));
|
|
*(short *)ptr = EM_page_no;
|
|
|
|
FORGETBLOCK(storage_ID)
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : set_name
|
|
|
|
PURPOSE : writes a name into the name section of the handle data
|
|
storage area
|
|
|
|
RETURNED STATUS :
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL void set_name IFN2(short, handle_no,
|
|
char *, new_name)
|
|
|
|
{
|
|
long storage_ID; /* host dependant storage */
|
|
/* identifier, usually a ptr. */
|
|
unsigned char *ptr; /* pointer to storage area */
|
|
|
|
|
|
storage_ID = handle[handle_no];
|
|
|
|
ptr = USEBLOCK(storage_ID);
|
|
/*
|
|
* offset pointer to correct position
|
|
*/
|
|
|
|
ptr += NAME_OFFSET;
|
|
strncpy((char *)ptr, new_name, NAME_LENGTH);
|
|
|
|
FORGETBLOCK(storage_ID)
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : get_no_pages
|
|
|
|
PURPOSE : gets the number of pages assigned to the specified handle
|
|
|
|
RETURNED STATUS : no of pages returned
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL short get_no_pages IFN1(short, handle_no)
|
|
|
|
{
|
|
long storage_ID; /* host dependant storage */
|
|
/* identifier, usually a ptr. */
|
|
byte *ptr; /* pointer to storage area */
|
|
short no_pages; /* no. of pages in handle */
|
|
|
|
storage_ID = handle[handle_no];
|
|
|
|
ptr = USEBLOCK(storage_ID);
|
|
|
|
no_pages = *(short *)ptr;
|
|
|
|
FORGETBLOCK(storage_ID)
|
|
|
|
return(no_pages);
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : get_EMpage_no
|
|
|
|
PURPOSE : returns the Expanded Memory page no. used for the
|
|
specified logical page in the given handle
|
|
|
|
RETURNED STATUS : Expanded Memory page no. returned
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL short get_EMpage_no IFN2(short, handle_no,
|
|
short, logical_page_no)
|
|
|
|
{
|
|
long storage_ID; /* host dependant storage */
|
|
/* identifier, usually a ptr. */
|
|
byte *ptr; /* pointer to storage area */
|
|
short EM_page_no; /* Expanded Memory page number */
|
|
|
|
storage_ID = handle[handle_no];
|
|
|
|
ptr = USEBLOCK(storage_ID);
|
|
/*
|
|
* offset pointer to correct position
|
|
*/
|
|
|
|
ptr += (page_offset +(logical_page_no * NSIZE));
|
|
EM_page_no = *(short *)ptr;
|
|
|
|
FORGETBLOCK(storage_ID)
|
|
|
|
return(EM_page_no);
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : get_map_no
|
|
|
|
PURPOSE : returns the Expanded Memory page no. saved in the map
|
|
attached to the given handle
|
|
|
|
RETURNED STATUS : page no. in map returned
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL short get_map_no IFN2(short, handle_no,
|
|
unsigned char, physical_page_no)
|
|
|
|
{
|
|
long storage_ID; /* host dependant storage */
|
|
/* identifier, usually a ptr. */
|
|
unsigned char *ptr; /* pointer to storage area */
|
|
short EM_page_no; /* Expanded Memory page number */
|
|
|
|
storage_ID = handle[handle_no];
|
|
|
|
ptr = USEBLOCK(storage_ID);
|
|
/*
|
|
* offset pointer to correct position
|
|
*/
|
|
|
|
ptr += (MAP_OFFSET +(physical_page_no * NSIZE));
|
|
EM_page_no = *(short *)ptr;
|
|
|
|
FORGETBLOCK(storage_ID)
|
|
|
|
return(EM_page_no);
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : get_name
|
|
|
|
PURPOSE : returns a pointer to the name assigned to the given handle
|
|
|
|
RETURNED STATUS :
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL char *get_name IFN1(short, handle_no)
|
|
|
|
{
|
|
long storage_ID; /* host dependant storage */
|
|
/* identifier, usually a ptr. */
|
|
unsigned char *ptr; /* pointer to storage area */
|
|
|
|
storage_ID = handle[handle_no];
|
|
|
|
ptr = USEBLOCK(storage_ID);
|
|
/*
|
|
* offset pointer to correct position
|
|
*/
|
|
|
|
ptr += NAME_OFFSET;
|
|
strncpy(name, (char *)ptr, NAME_LENGTH);
|
|
|
|
FORGETBLOCK(storage_ID)
|
|
|
|
return(name);
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : alloc_page
|
|
|
|
PURPOSE : allocates a page from expanded memory
|
|
|
|
RETURNED : >=0 = SUCCESS - EM page no. returned
|
|
<0 = FAILURE - error occured in trying to allocate page
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL short alloc_page IFN0()
|
|
|
|
{
|
|
short EM_page_no; /* EM_page_no to be returned */
|
|
|
|
|
|
if ((EM_page_no = host_alloc_page()) == FAILURE)
|
|
return(FAILURE);
|
|
|
|
unallocated_pages--;
|
|
|
|
return(EM_page_no);
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : free_page
|
|
|
|
PURPOSE : frees a page of expanded memory for further use
|
|
|
|
RETURNED : SUCCESS - page freed successfully
|
|
FAILURE - unable to free page
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL int free_page IFN1(short, EM_page_no)
|
|
|
|
{
|
|
|
|
short physical_page_no;
|
|
|
|
if (EM_page_no > total_pages)
|
|
return(FAILURE);
|
|
|
|
/* Removed from mapped pages table */
|
|
|
|
for (physical_page_no=0; physical_page_no < no_phys_pages; physical_page_no++) {
|
|
|
|
if (EM_page_mapped[physical_page_no] == EM_page_no) {
|
|
EM_page_mapped[physical_page_no] = UNMAPPED;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (host_free_page(EM_page_no) != SUCCESS)
|
|
return(FAILURE);
|
|
|
|
unallocated_pages++;
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
#ifndef NTVDM
|
|
/*
|
|
========================================================================
|
|
|
|
FUNCTION : page_already_mapped
|
|
|
|
PURPOSE : function to determine whether a EMM page is already
|
|
mapped to a different physical page within intel
|
|
memory
|
|
|
|
RETURNED : count of number of pages in addition to the page
|
|
passed which are mapped to the same logical page.
|
|
The page number of one of these mirror pages is
|
|
also returned via the pointer passed as an argument.
|
|
|
|
DESCRIPTION :
|
|
|
|
========================================================================
|
|
*/
|
|
|
|
GLOBAL ULONG
|
|
page_already_mapped IFN2(short, EM_page_no,
|
|
unsigned char *, physical_page_no)
|
|
|
|
{
|
|
unsigned char page, orig_page;
|
|
ULONG map_count;
|
|
|
|
map_count = 0;
|
|
orig_page = *physical_page_no;
|
|
|
|
for( page = 0; page < (unsigned char) no_phys_pages; page++ )
|
|
{
|
|
if ((EM_page_mapped[page] == EM_page_no) &&
|
|
(page != orig_page ))
|
|
{
|
|
sure_note_trace2( LIM_VERBOSE,
|
|
"log page %x mapped to phys page %x",
|
|
EM_page_no, page);
|
|
|
|
*physical_page_no = page;
|
|
map_count++;
|
|
}
|
|
}
|
|
|
|
return( map_count );
|
|
}
|
|
|
|
|
|
LOCAL VOID
|
|
connect_MM_LIM_page IFN2( USHORT, segment, SHORT, EM_page_no )
|
|
{
|
|
ULONG eff_addr;
|
|
|
|
#ifdef PROD
|
|
UNUSED(EM_page_no);
|
|
#endif
|
|
|
|
assert2( NO, "Connecting multi-mapped page, %d, at %x",
|
|
EM_page_no, segment );
|
|
|
|
eff_addr = effective_addr( segment, 0 );
|
|
sas_connect_memory( eff_addr, eff_addr + EMM_PAGE_SIZE - 1,
|
|
SAS_MM_LIM );
|
|
}
|
|
|
|
LOCAL VOID
|
|
disconnect_MM_LIM_page IFN4( USHORT, segment, SHORT, EM_page_no,
|
|
ULONG, map_count, unsigned char, physical_page_no )
|
|
{
|
|
ULONG eff_addr;
|
|
|
|
#ifdef PROD
|
|
UNUSED(EM_page_no);
|
|
#endif
|
|
|
|
sure_note_trace2(LIM_VERBOSE,
|
|
"Unmapping multi-mapped page, %d, at %x",
|
|
EM_page_no, segment );
|
|
|
|
eff_addr = effective_addr( segment, 0 );
|
|
sas_connect_memory( eff_addr, eff_addr + EMM_PAGE_SIZE - 1, SAS_RAM );
|
|
|
|
if( map_count == 1 )
|
|
{
|
|
/*
|
|
* We have to disconnect the last page of this group,
|
|
* by connecting it as SAS_RAM.
|
|
*/
|
|
|
|
segment = physical_page[physical_page_no];
|
|
eff_addr = effective_addr( segment, 0 );
|
|
|
|
sure_note_trace2(LIM_VERBOSE,
|
|
"Unmapping last multi-mapped page, %d, at %x",
|
|
EM_page_no, segment );
|
|
|
|
sas_connect_memory( eff_addr, eff_addr + EMM_PAGE_SIZE - 1,
|
|
SAS_RAM );
|
|
}
|
|
}
|
|
|
|
#endif /* !NTVDM */
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
FUNCTION : map_page
|
|
|
|
PURPOSE : maps a page from expanded memory into Intel physical
|
|
address space
|
|
|
|
RETURNED : SUCCESS - page mapped successfully
|
|
FAILURE - unable to map page
|
|
|
|
DESCRIPTION :
|
|
|
|
========================================================================
|
|
*/
|
|
GLOBAL int map_page IFN2(short, EM_page_no,
|
|
unsigned char, physical_page_no)
|
|
|
|
{
|
|
USHORT segment; /* segment address of page in */
|
|
/* physical address space */
|
|
unsigned char phys_page;
|
|
ULONG map_count;
|
|
|
|
segment = physical_page[physical_page_no];
|
|
|
|
/*
|
|
* make sure that a page is not already mapped in
|
|
* if it is - return it to Expanded Memory
|
|
*/
|
|
sure_note_trace2(LIM_VERBOSE,
|
|
"map page %#x to phys page %#x",
|
|
EM_page_no,physical_page_no);
|
|
|
|
if(EM_page_mapped[physical_page_no] != EMPTY)
|
|
{
|
|
sure_note_trace1(LIM_VERBOSE,
|
|
"phys page already mapped to page %#x",
|
|
EM_page_mapped[physical_page_no]);
|
|
|
|
if(EM_page_mapped[physical_page_no] == EM_page_no)
|
|
{
|
|
sure_note_trace0(LIM_VERBOSE,
|
|
"remap of same page, so do nothing");
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
#ifndef NTVDM
|
|
/*
|
|
* We want to return the current contents of this physical
|
|
* page to the logical page ( to sync up the logical page ).
|
|
* We have to check first that this physical page is not a
|
|
* mirror of some other page - if it is we have to disconnect
|
|
* it from the group of pages it is mirroring.
|
|
*/
|
|
|
|
phys_page = physical_page_no;
|
|
|
|
if( map_count = page_already_mapped(
|
|
EM_page_mapped[physical_page_no], &phys_page))
|
|
{
|
|
disconnect_MM_LIM_page( segment, EM_page_no,
|
|
map_count, phys_page );
|
|
}
|
|
|
|
/*
|
|
* We can now unmap the physical page and indicate
|
|
* that it is really unmapped.
|
|
*/
|
|
if(host_unmap_page(segment,
|
|
EM_page_mapped[physical_page_no]) != SUCCESS)
|
|
{
|
|
return(FAILURE);
|
|
}
|
|
EM_page_mapped [physical_page_no] = EMPTY;
|
|
#endif
|
|
|
|
}
|
|
#ifndef NTVDM
|
|
|
|
/*
|
|
* If this logical page is already mapped, make sure the
|
|
* new mapping has an up to date copy
|
|
*/
|
|
|
|
phys_page = physical_page_no;
|
|
|
|
if (page_already_mapped(EM_page_no, &phys_page))
|
|
{
|
|
/*
|
|
* We now want to get the LIM logical page up to date with
|
|
* the physical pages that are currently mapped to it. We
|
|
* don't want to set EM_page_mapped [phys_page] to EMPTY
|
|
* after the host_unmap_page(). If we did we wouldn't notice
|
|
* that we had a multiply-mapped page and the patch up code
|
|
* wouldn't get called.
|
|
*/
|
|
|
|
host_update_logical_page( physical_page[phys_page],
|
|
EM_page_no );
|
|
|
|
/*
|
|
* Connect new page and "mirror" page as MM_LIM. This may
|
|
* mean some pages get connected as MM_LIM multiple times
|
|
* - inefficient but not wrong otherwise. This connection
|
|
* has to be made for all hosts - even those that can do
|
|
* mapping themselves. This is to make sure that the CPU
|
|
* data structures associated with all pages get updated
|
|
* when a multi-mapped write occurs.
|
|
*/
|
|
|
|
connect_MM_LIM_page( segment, EM_page_no );
|
|
|
|
connect_MM_LIM_page( physical_page[phys_page], EM_page_no );
|
|
}
|
|
#endif
|
|
if(host_map_page(EM_page_no, segment) != SUCCESS)
|
|
return(FAILURE);
|
|
|
|
EM_page_mapped[physical_page_no] = EM_page_no;
|
|
|
|
sure_note_trace0(LIM_VERBOSE,"map OK");
|
|
return(SUCCESS);
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
FUNCTION : unmap_page
|
|
|
|
PURPOSE : unmaps a page from Intel physical address space back to
|
|
expanded memory
|
|
|
|
RETURNED : SUCCESS - page unmapped successfully
|
|
FAILURE - error in unmapping page
|
|
|
|
DESCRIPTION :
|
|
|
|
========================================================================
|
|
*/
|
|
GLOBAL int unmap_page IFN1(unsigned char, physical_page_no)
|
|
|
|
{
|
|
short EM_page_no; /* EM_page_no currently mapped */
|
|
unsigned short segment; /* segment address of page in */
|
|
/* physical address space */
|
|
SHORT phys_page;
|
|
ULONG map_count;
|
|
|
|
sure_note_trace1( LIM_VERBOSE,
|
|
"unmap phys page %#x",physical_page_no);
|
|
|
|
segment = physical_page[physical_page_no];
|
|
|
|
if((EM_page_no = EM_page_mapped[physical_page_no]) == EMPTY)
|
|
{
|
|
/*
|
|
* Already done
|
|
*/
|
|
sure_note_trace0( LIM_VERBOSE,
|
|
"already unmapped, so do nothing");
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
phys_page = physical_page_no;
|
|
|
|
#ifndef NTVDM
|
|
if( map_count = page_already_mapped( EM_page_no, (unsigned char *)&phys_page ))
|
|
{
|
|
disconnect_MM_LIM_page( segment, EM_page_no,
|
|
map_count, phys_page );
|
|
}
|
|
#endif
|
|
|
|
if(host_unmap_page(segment, EM_page_no) != SUCCESS)
|
|
return(FAILURE);
|
|
|
|
EM_page_mapped[physical_page_no] = EMPTY;
|
|
|
|
sure_note_trace0(LIM_VERBOSE,"unmap OK");
|
|
return(SUCCESS);
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : map_saved
|
|
|
|
PURPOSE : Checks to see if a map has been saved for the specified
|
|
handle
|
|
|
|
RETURNED STATUS : TRUE - A map is saved for this handle
|
|
FALSE - No map has been saved
|
|
|
|
DESCRIPTION : checks the first entry in the map for the value 'FREE'
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL boolean map_saved IFN1(short, handle_no)
|
|
|
|
{
|
|
long storage_ID; /* host dependant storage */
|
|
/* identifier, usually a ptr. */
|
|
unsigned char *ptr; /* pointer to storage area */
|
|
short status; /* value read from map */
|
|
|
|
storage_ID = handle[handle_no];
|
|
ptr = USEBLOCK(storage_ID);
|
|
|
|
/*
|
|
* offset pointer to correct position
|
|
*/
|
|
|
|
ptr += MAP_OFFSET;
|
|
status = *(short *)ptr;
|
|
|
|
FORGETBLOCK(storage_ID)
|
|
|
|
return((status == FREE) ? FALSE : TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : save_map
|
|
|
|
PURPOSE : takes a copy of the EM_page_mapped array and store it in
|
|
the map section of the handle data storage area
|
|
|
|
RETURNED STATUS : SUCCESS - everything OK
|
|
FAILURE - invalid segment no. passed in src array
|
|
|
|
DESCRIPTION : if handle_no is >= 0 the map is stored in the data area
|
|
assigned to that handle
|
|
if handle_no == -1 the map is stored in the array pointed
|
|
to by dst_segment:dst_offset
|
|
if handle_no == -2 only the pages specified by the segment
|
|
addresses in the src array (pointed to by
|
|
src_segment:src_offset) are saved in the dst array
|
|
(pointed to by dst_segment:dst_offset).
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL int save_map IFN5(short, handle_no,
|
|
unsigned short, dst_segment,
|
|
unsigned short, dst_offset,
|
|
unsigned short, src_segment,
|
|
unsigned short, src_offset)
|
|
|
|
{
|
|
unsigned short offset, /* temp offset variable */
|
|
segment; /* segment address to be saved */
|
|
short i, /* loop counter */
|
|
page_no, /* physical page no. */
|
|
no_to_save; /* no of pages in src array */
|
|
|
|
if(handle_no >= 0)
|
|
for (i = 0; i < no_phys_pages; i++)
|
|
set_map_no(handle_no, i, EM_page_mapped[i]);
|
|
|
|
else if(handle_no == -1)
|
|
for(i = 0; i < no_phys_pages; i++)
|
|
{
|
|
write_intel_word(dst_segment, dst_offset, EM_page_mapped[i]);
|
|
dst_offset +=2;
|
|
}
|
|
|
|
else if(handle_no == -2)
|
|
{
|
|
offset = dst_offset;
|
|
for(i = 0; i < no_phys_pages; i++)
|
|
{
|
|
#ifdef NTVDM
|
|
write_intel_word(dst_segment, offset, LEAVE);
|
|
#else
|
|
write_intel_word(dst_segment, offset, EMPTY);
|
|
#endif
|
|
offset += 2;
|
|
}
|
|
read_intel_word(src_segment, src_offset, (word *)&no_to_save);
|
|
for (i = 0; i < no_to_save; i++)
|
|
{
|
|
src_offset += 2;
|
|
read_intel_word(src_segment, src_offset, &segment);
|
|
/*
|
|
* Find Physical page no.
|
|
*/
|
|
page_no = 0;
|
|
do
|
|
if(segment == physical_page[page_no])
|
|
break;
|
|
while(++page_no < no_phys_pages);
|
|
|
|
if(page_no >= no_phys_pages)
|
|
return (FAILURE);
|
|
/*
|
|
* Save EM page number in destination array
|
|
*/
|
|
offset = dst_offset + (page_no * 2);
|
|
write_intel_word(dst_segment, offset, EM_page_mapped[page_no]);
|
|
}
|
|
}
|
|
return(SUCCESS);
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : restore_map
|
|
|
|
PURPOSE : reads the specified map and returns 2 arrays specifying
|
|
which pages have to be mapped out and which ones have to be
|
|
mapped in
|
|
|
|
RETURNED STATUS : SUCCESS - Map read successfully
|
|
|
|
|
|
DESCRIPTION : A +ve handle number indicates that the map is stored
|
|
within the handle data area.
|
|
If the handle number is -ve the map will be read from the
|
|
data pointed to by segment:offset
|
|
|
|
Only page out - if there is a page currently mapped in and
|
|
it is not being replaced by a copy of itself or an empty
|
|
page
|
|
Only page in - if new page is different to existing one
|
|
and it is not empty
|
|
|
|
=========================================================================
|
|
*/
|
|
#ifdef ANSI
|
|
GLOBAL int restore_map (short handle_no,
|
|
unsigned short segment,
|
|
unsigned short offset,
|
|
short pages_out[],
|
|
short pages_in[])
|
|
#else
|
|
GLOBAL int restore_map (handle_no, segment, offset, pages_out, pages_in)
|
|
short handle_no;
|
|
unsigned short segment;
|
|
unsigned short offset;
|
|
short pages_out[];
|
|
short pages_in[];
|
|
#endif /* ANSI */
|
|
{
|
|
short i, /* loop counter */
|
|
new_page, /* page number read from map */
|
|
old_page; /* existing page number */
|
|
|
|
for(i = 0; i < no_phys_pages; i++)
|
|
{
|
|
if(handle_no >= 0)
|
|
new_page = get_map_no(handle_no, i);
|
|
else
|
|
{
|
|
read_intel_word(segment, offset, (word *)&new_page);
|
|
offset += 2;
|
|
#ifdef NTVDM
|
|
if(new_page < LEAVE || new_page >= total_pages)
|
|
#else
|
|
if(new_page < EMPTY || new_page >= total_pages)
|
|
#endif /* NTVDM */
|
|
return(FAILURE);
|
|
}
|
|
old_page = EM_page_mapped[i];
|
|
|
|
/*
|
|
if(old_page != EMPTY && new_page != EMPTY && old_page != new_page )
|
|
*/
|
|
/* need to do unmap to empty state case to update the page copy in the LIM
|
|
space in case of new maps of that page to other LIM slots. */
|
|
#ifdef NTVDM
|
|
if(old_page != EMPTY && old_page != new_page && new_page != LEAVE)
|
|
#else
|
|
if(old_page != EMPTY && old_page != new_page )
|
|
#endif
|
|
pages_out[i] = old_page;
|
|
else
|
|
pages_out[i] = EMPTY;
|
|
|
|
#ifdef NTVDM
|
|
if(new_page != EMPTY && new_page != old_page && new_page != LEAVE)
|
|
#else
|
|
if(new_page != EMPTY && new_page != old_page)
|
|
#endif
|
|
pages_in[i] = new_page;
|
|
else
|
|
pages_in[i] = EMPTY;
|
|
}
|
|
if(handle_no >= 0)
|
|
set_map_no(handle_no, 0, FREE);
|
|
|
|
return(SUCCESS);
|
|
}
|
|
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : copy_exchange_data
|
|
|
|
PURPOSE : copies or exchanges data between conventional and
|
|
expanded memory
|
|
|
|
RETURNED STATUS : SUCCESS - everything ok
|
|
FAILURE - Error ocurred in copying data
|
|
|
|
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
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL int copy_exchange_data IFN8(unsigned char, type,
|
|
short, src_handle,
|
|
unsigned short, src_seg_page,
|
|
unsigned short, src_offset,
|
|
short, dst_handle,
|
|
unsigned short, dst_seg_page,
|
|
unsigned short, dst_offset,
|
|
unsigned long, length)
|
|
|
|
{
|
|
short dst_EMpage, /* EM page no . of destination */
|
|
src_EMpage; /* EM page no. of source */
|
|
int page_no; /* phys. page no. of mapped page*/
|
|
|
|
/*
|
|
* First check to see if the expanded memory page is mapped
|
|
* if it is - change the type to deal directly with the
|
|
* physical page that it is mapped to
|
|
*/
|
|
if( type & 1)
|
|
{
|
|
dst_EMpage = get_EMpage_no(dst_handle, dst_seg_page);
|
|
if((page_no = page_status(dst_EMpage)) != UNMAPPED )
|
|
{
|
|
dst_seg_page = physical_page[page_no];
|
|
type &= 6;
|
|
}
|
|
}
|
|
if( type & 2)
|
|
{
|
|
src_EMpage = get_EMpage_no(src_handle, src_seg_page);
|
|
if((page_no = page_status(src_EMpage)) != UNMAPPED )
|
|
{
|
|
src_seg_page = physical_page[page_no];
|
|
type &= 5;
|
|
}
|
|
}
|
|
|
|
switch(type)
|
|
{
|
|
case 0: if(host_copy_con_to_con(length, src_seg_page, src_offset,
|
|
dst_seg_page, dst_offset) != SUCCESS)
|
|
return(FAILURE);
|
|
break;
|
|
|
|
case 1: if(host_copy_con_to_EM(length, src_seg_page, src_offset,
|
|
dst_EMpage, dst_offset) != SUCCESS)
|
|
return(FAILURE);
|
|
break;
|
|
|
|
case 2: if(host_copy_EM_to_con(length, src_EMpage, src_offset,
|
|
dst_seg_page, dst_offset) != SUCCESS)
|
|
return(FAILURE);
|
|
break;
|
|
|
|
case 3: if(host_copy_EM_to_EM(length, src_EMpage, src_offset,
|
|
dst_EMpage, dst_offset) != SUCCESS)
|
|
return(FAILURE);
|
|
break;
|
|
|
|
case 4: if(host_exchg_con_to_con(length, src_seg_page, src_offset,
|
|
dst_seg_page, dst_offset) != SUCCESS)
|
|
return(FAILURE);
|
|
break;
|
|
|
|
case 5: if(host_exchg_con_to_EM(length, src_seg_page, src_offset,
|
|
dst_EMpage, dst_offset) != SUCCESS)
|
|
return(FAILURE);
|
|
break;
|
|
|
|
case 6: if(host_exchg_con_to_EM(length, dst_seg_page, dst_offset,
|
|
src_EMpage, src_offset) != SUCCESS)
|
|
return(FAILURE);
|
|
break;
|
|
|
|
case 7: if(host_exchg_EM_to_EM(length, src_EMpage, src_offset,
|
|
dst_EMpage, dst_offset) != SUCCESS)
|
|
return(FAILURE);
|
|
break;
|
|
|
|
default: return(FAILURE);
|
|
}
|
|
return(SUCCESS);
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
FUNCTION : page_status
|
|
|
|
PURPOSE : checks if a particular EM page is mapped or not
|
|
|
|
RETURNED STATUS : page_no - physical page no returned if mapped
|
|
UNMAPPED - returned if not mapped
|
|
|
|
DESCRIPTION :
|
|
|
|
========================================================================
|
|
*/
|
|
|
|
GLOBAL int page_status IFN1(short, EMpage_no)
|
|
{
|
|
short physical_page_no = 0;
|
|
/* position of page in physical memory */
|
|
|
|
do
|
|
if(EM_page_mapped[physical_page_no] == EMpage_no)
|
|
break;
|
|
while(++physical_page_no < no_phys_pages );
|
|
|
|
if(physical_page_no >= no_phys_pages)
|
|
return(UNMAPPED);
|
|
else
|
|
return(physical_page_no);
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
FUNCTION : phys_page_from_addr
|
|
|
|
PURPOSE : determines the physical page number of a LIM page
|
|
from its Intel address.
|
|
|
|
RETURNED STATUS : The physical page containing the LIM address.
|
|
|
|
DESCRIPTION :
|
|
|
|
=======================================================================
|
|
*/
|
|
|
|
LOCAL SHORT
|
|
phys_page_from_addr IFN1( sys_addr, address )
|
|
|
|
{
|
|
sys_addr start;
|
|
|
|
start = effective_addr( EM_start, 0x0 );
|
|
|
|
return( (ULONG)(( address - start ) / EMM_PAGE_SIZE ));
|
|
}
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
FUNCTION : get_total_pages
|
|
get_unallocated_pages
|
|
get_base_address
|
|
get_total_handles
|
|
get_total_open_handles
|
|
get_no_phys_pages
|
|
get_page_seg
|
|
get_map_size
|
|
|
|
PURPOSE : simply returns the reqested variables, to avoid
|
|
having to use globals
|
|
|
|
|
|
RETURNED STATUS : the following variables are returned , depending upon
|
|
the routine called:-
|
|
total_pages
|
|
unallocated_pages
|
|
base_address
|
|
total_handles
|
|
total_open_handles
|
|
no_phys_pages
|
|
physical_page[i]
|
|
map_size
|
|
|
|
DESCRIPTION :
|
|
|
|
========================================================================
|
|
*/
|
|
|
|
#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_LIM2.seg"
|
|
#endif
|
|
|
|
GLOBAL short get_total_pages IFN0()
|
|
{
|
|
return(total_pages);
|
|
}
|
|
|
|
#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
|
|
|
|
GLOBAL short get_unallocated_pages IFN0()
|
|
{
|
|
return(unallocated_pages);
|
|
}
|
|
|
|
GLOBAL unsigned short get_base_address IFN0()
|
|
{
|
|
#ifdef NTVDM
|
|
return(physical_page[0]);
|
|
#else
|
|
return(EM_start);
|
|
#endif
|
|
}
|
|
|
|
GLOBAL short get_total_handles IFN0()
|
|
{
|
|
return(total_handles);
|
|
}
|
|
|
|
GLOBAL short get_total_open_handles IFN0()
|
|
{
|
|
return(total_open_handles);
|
|
}
|
|
|
|
GLOBAL short get_no_phys_pages IFN0()
|
|
{
|
|
return(no_phys_pages);
|
|
}
|
|
|
|
GLOBAL unsigned short get_page_seg IFN1(unsigned char, page_no)
|
|
{
|
|
return(physical_page[page_no]);
|
|
}
|
|
|
|
GLOBAL short get_map_size IFN0()
|
|
{
|
|
return(map_size);
|
|
}
|
|
|
|
#ifdef NTVDM
|
|
GLOBAL short get_segment_page_no(unsigned short segment)
|
|
{
|
|
#if defined(LARGE_FRAME) && !defined(MONITOR)
|
|
short i
|
|
for (i = 0; i < no_phys_pages; i++)
|
|
if (physical_page[i] == segment)
|
|
break;
|
|
return(i);
|
|
#else
|
|
return((segment - physical_page[0]) / EMM_PAGE_SIZE);
|
|
#endif
|
|
|
|
}
|
|
GLOBAL unsigned short get_no_altreg_sets(void)
|
|
{
|
|
return(no_altreg_sets);
|
|
}
|
|
|
|
GLOBAL unsigned short get_active_altreg_set(void)
|
|
{
|
|
return(active_altreg_set);
|
|
}
|
|
|
|
GLOBAL boolean altreg_set_ok(unsigned short set)
|
|
{
|
|
return(set < no_altreg_sets &&
|
|
(altreg_alloc_mask[set >> 3] & (1 << (set & 0x07))));
|
|
|
|
}
|
|
|
|
#if defined (NTVDM) && defined(MONITOR) && !defined(PROD)
|
|
/* these functions are provided for monitor to verify that
|
|
* it has the same definitions of EMM_PAGE_SIZE and INTEL_PAGE_SIZE as
|
|
* ours.
|
|
*/
|
|
|
|
GLOBAL unsigned short get_emm_page_size(void)
|
|
{
|
|
return ((unsigned short)EMM_PAGE_SIZE);
|
|
}
|
|
GLOBAL unsigned short get_intel_page_size(void)
|
|
{
|
|
return ((unsigned short) INTEL_PAGE_SIZE);
|
|
}
|
|
#endif
|
|
|
|
/* allocate a free alt mapping register set */
|
|
|
|
GLOBAL boolean allocate_altreg_set(unsigned short *altreg_set)
|
|
{
|
|
short byte_offset, bit_offset;
|
|
short *page_mapped_ptr;
|
|
IU8 mask;
|
|
int i;
|
|
/* this check is very important because we ** probably ** have
|
|
* several unused bits in the allocation mask array
|
|
*/
|
|
if (free_altreg_sets == 0)
|
|
return (FALSE);
|
|
|
|
/* use quick and dirty way to allocate a set */
|
|
if (next_free_altreg_set < no_altreg_sets) {
|
|
altreg_alloc_mask[next_free_altreg_set >> 3] |=
|
|
(0x1 << (next_free_altreg_set & 0x07));
|
|
*altreg_set = next_free_altreg_set++;
|
|
}
|
|
else {
|
|
for (byte_offset = 0; byte_offset < no_altreg_sets; byte_offset++) {
|
|
if (altreg_alloc_mask[byte_offset] != 0xFF) {
|
|
mask = altreg_alloc_mask[byte_offset];
|
|
bit_offset = 0;
|
|
while (mask & (1 << bit_offset))
|
|
bit_offset++;
|
|
break;
|
|
}
|
|
}
|
|
altreg_alloc_mask[byte_offset] |= (1 << bit_offset);
|
|
*altreg_set = byte_offset * 8 + bit_offset;
|
|
}
|
|
/* a new alt reg set is just allocated, initialize its
|
|
* mapping register to the current active set
|
|
*/
|
|
page_mapped_ptr = GET_EM_PAGE_MAPPED_PTR(*altreg_set);
|
|
for (i = 0; i < no_phys_pages; i++)
|
|
page_mapped_ptr[i] = EM_page_mapped[i];
|
|
return TRUE;
|
|
}
|
|
/* free the given alt mapping register set */
|
|
GLOBAL boolean deallocate_altreg_set(short set)
|
|
{
|
|
|
|
/* can not deallocate set 0 or active set */
|
|
if (set != 0 && set != active_altreg_set && set < no_altreg_sets &&
|
|
altreg_alloc_mask[set >> 3] & (1 << (set &0x07))) {
|
|
|
|
altreg_alloc_mask[set >> 3] &= (0xFE << (set & 0x07));
|
|
free_altreg_sets++;
|
|
if (free_altreg_sets == (no_altreg_sets - 1))
|
|
next_free_altreg_set = 1;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/* This function activate the given alt mapping register set
|
|
* input: alt reg set to be activated.
|
|
* output: TRUE if the given set is activated.
|
|
* FALSE if the given set is not activated.
|
|
*/
|
|
|
|
GLOBAL boolean activate_altreg_set(unsigned short set, short * page_in)
|
|
{
|
|
int i;
|
|
short * page_out, *page_in_ptr;
|
|
short new_page, old_page, segment;
|
|
|
|
|
|
if (active_altreg_set == set && page_in == NULL)
|
|
return TRUE;
|
|
|
|
/* get the mapping array to be mapped in*/
|
|
page_in_ptr = GET_EM_PAGE_MAPPED_PTR(set);
|
|
|
|
/* if no page-in override, use the altreg set current mapping */
|
|
if (page_in == NULL)
|
|
page_in = page_in_ptr;
|
|
|
|
/* the active altreg is being paged out */
|
|
page_out = GET_EM_PAGE_MAPPED_PTR(active_altreg_set);
|
|
for ( i = 0; i < no_phys_pages; i++) {
|
|
new_page = page_in[i];
|
|
old_page = page_out[i];
|
|
segment = physical_page[i];
|
|
|
|
if (old_page != EMPTY && old_page != new_page) {
|
|
if (host_unmap_page(segment, old_page) != SUCCESS)
|
|
return FALSE;
|
|
}
|
|
if(new_page != EMPTY && new_page != old_page) {
|
|
if (host_map_page(new_page, segment) != SUCCESS)
|
|
return FALSE;
|
|
}
|
|
/* update the active-to-be set mapping */
|
|
page_in_ptr[i] = new_page;
|
|
}
|
|
active_altreg_set = set;
|
|
EM_page_mapped = page_in_ptr;
|
|
return TRUE;
|
|
}
|
|
#endif /* NTVDM */
|
|
|
|
#ifndef NTVDM
|
|
|
|
/*
|
|
========================================================================
|
|
|
|
FUNCTION : LIM_b_write,
|
|
LIM_w_write,
|
|
LIM_str_write
|
|
patch_pages
|
|
|
|
PURPOSE : LIM byte, word & string - called from write check
|
|
failure code in the CPU when a write to a multi-mapped
|
|
LIM page is detected.
|
|
patch_pages - generic code called from the other
|
|
three routines.
|
|
|
|
RETURNED STATUS : None.
|
|
|
|
DESCRIPTION :
|
|
|
|
========================================================================
|
|
*/
|
|
|
|
LOCAL VOID
|
|
patch_one_page_partial IFN4( sys_addr, intel_addr, sys_addr, eff_addr,
|
|
MM_LIM_op_type, type, ULONG, data )
|
|
|
|
{
|
|
ULONG check_len;
|
|
|
|
UNUSED( intel_addr ); /* Used in patch_one_page_full() */
|
|
|
|
switch( type )
|
|
{
|
|
case BYTE_OP:
|
|
check_len = 1;
|
|
break;
|
|
|
|
case WORD_OP:
|
|
check_len = 2;
|
|
break;
|
|
|
|
case STR_OP:
|
|
check_len = data;
|
|
break;
|
|
}
|
|
|
|
sas_overwrite_memory( eff_addr, check_len );
|
|
}
|
|
|
|
LOCAL VOID
|
|
patch_one_page_full IFN4( sys_addr, intel_addr, sys_addr, eff_addr,
|
|
MM_LIM_op_type, type, ULONG, data )
|
|
|
|
{
|
|
sys_addr check_addr;
|
|
ULONG check_len;
|
|
|
|
switch( type )
|
|
{
|
|
case BYTE_OP:
|
|
check_addr = eff_addr;
|
|
check_len = 1;
|
|
sas_store_no_check( eff_addr, data );
|
|
break;
|
|
|
|
case WORD_OP:
|
|
check_addr = eff_addr;
|
|
check_len = 2;
|
|
sas_storew_no_check( eff_addr, data );
|
|
break;
|
|
|
|
case STR_OP:
|
|
check_addr = eff_addr;
|
|
check_len = data;
|
|
do
|
|
{
|
|
sas_store_no_check( eff_addr,
|
|
sas_hw_at_no_check(
|
|
intel_addr ));
|
|
intel_addr++;
|
|
eff_addr++;
|
|
}
|
|
while( --data );
|
|
break;
|
|
}
|
|
|
|
sas_overwrite_memory( check_addr, check_len );
|
|
}
|
|
|
|
LOCAL VOID
|
|
patch_pages IFN6( MM_LIM_op_type, type, ULONG, offset,
|
|
SHORT, EM_page_no, SHORT, phys_page_no,
|
|
ULONG, data, sys_addr, intel_addr )
|
|
|
|
{
|
|
LONG cnt01;
|
|
sys_addr eff_addr;
|
|
|
|
for( cnt01 = 0; cnt01 < get_no_phys_pages(); cnt01++ )
|
|
{
|
|
if(( EM_page_mapped[cnt01] == EM_page_no ) &&
|
|
( cnt01 != phys_page_no ))
|
|
{
|
|
eff_addr = effective_addr( get_page_seg(cnt01),
|
|
offset );
|
|
|
|
host_patch_one_page( intel_addr, eff_addr, type, data );
|
|
|
|
sure_note_trace1(LIM_VERBOSE,
|
|
"MM LIM write type %d", type );
|
|
sure_note_trace2(LIM_VERBOSE,
|
|
"log page 0x%x, phs page 0x%x",
|
|
EM_page_no, cnt01 );
|
|
}
|
|
}
|
|
}
|
|
|
|
GLOBAL VOID
|
|
LIM_b_write IFN1( sys_addr, intel_addr )
|
|
|
|
{
|
|
ULONG limdata;
|
|
SHORT EM_page_no, phys_page_no;
|
|
word offset;
|
|
|
|
phys_page_no = phys_page_from_addr( intel_addr );
|
|
|
|
offset = intel_addr -
|
|
effective_addr( get_page_seg(phys_page_no), 0x0 );
|
|
|
|
EM_page_no = EM_page_mapped[phys_page_no];
|
|
|
|
/*
|
|
* Get the data written in order to patch up this
|
|
* page's buddy pages.
|
|
*/
|
|
|
|
limdata = (ULONG) sas_hw_at_no_check( intel_addr );
|
|
patch_pages( BYTE_OP, offset, EM_page_no, phys_page_no,
|
|
limdata, intel_addr );
|
|
|
|
/*
|
|
* Tell the CPU that this page has been written to.
|
|
*/
|
|
|
|
sas_overwrite_memory( intel_addr, 1 );
|
|
}
|
|
|
|
GLOBAL VOID
|
|
LIM_w_write IFN1( sys_addr, intel_addr )
|
|
|
|
{
|
|
ULONG limdata;
|
|
SHORT EM_page_no, phys_page_no;
|
|
word offset;
|
|
|
|
phys_page_no = phys_page_from_addr( intel_addr );
|
|
|
|
offset = intel_addr -
|
|
effective_addr( get_page_seg(phys_page_no), 0x0 );
|
|
|
|
EM_page_no = EM_page_mapped[phys_page_no];
|
|
|
|
limdata = (ULONG) sas_w_at_no_check( intel_addr );
|
|
patch_pages( WORD_OP, offset, EM_page_no, phys_page_no,
|
|
limdata, intel_addr );
|
|
|
|
sas_overwrite_memory( intel_addr, 2 );
|
|
}
|
|
|
|
GLOBAL VOID
|
|
LIM_str_write IFN2( sys_addr, intel_addr, ULONG, length )
|
|
|
|
{
|
|
SHORT EM_page_no, phys_page_no;
|
|
word offset;
|
|
|
|
phys_page_no = phys_page_from_addr( intel_addr );
|
|
|
|
offset = intel_addr -
|
|
effective_addr( get_page_seg(phys_page_no), 0x0 );
|
|
|
|
EM_page_no = EM_page_mapped[phys_page_no];
|
|
|
|
patch_pages( STR_OP, offset, EM_page_no, phys_page_no,
|
|
length, intel_addr );
|
|
|
|
sas_overwrite_memory( intel_addr, length );
|
|
}
|
|
#endif /* !NTVDM */
|
|
|
|
#ifndef PROD
|
|
/*
|
|
===========================================================================
|
|
|
|
FUNCTION : print_handle_data
|
|
|
|
PURPOSE : used for debugging only - prints all the data stored
|
|
for a given handle
|
|
|
|
RETURNED STATUS : none
|
|
|
|
DESCRIPTION :
|
|
|
|
=========================================================================
|
|
*/
|
|
GLOBAL void print_handle_data IFN1(short, handle_no)
|
|
|
|
{
|
|
long storage_ID;
|
|
byte *ptr;
|
|
short no_pages, i;
|
|
char *name_ptr;
|
|
short *map_ptr;
|
|
short *page_ptr;
|
|
|
|
if ((storage_ID = handle[handle_no]) == 0)
|
|
{
|
|
printf("Unassigned handle - No. %d\n",handle_no);
|
|
return;
|
|
}
|
|
ptr = USEBLOCK(storage_ID);
|
|
name_ptr = (char *)ptr + NAME_OFFSET;
|
|
map_ptr = (short *)(ptr + MAP_OFFSET);
|
|
page_ptr = (short *)(ptr + page_offset);
|
|
|
|
no_pages = *(short *)ptr;
|
|
printf("Handle No. %d\n",handle_no);
|
|
printf("No. of Pages = %d\n",no_pages);
|
|
printf("Name = '");
|
|
for(i=0;i<8;i++)
|
|
printf("%c",*name_ptr++);
|
|
printf("'\n");
|
|
printf("Map = ");
|
|
for(i=0;i<no_phys_pages;i++)
|
|
printf(" %d",*map_ptr++);
|
|
printf("\n");
|
|
for(i=0;i<no_pages;i++)
|
|
printf("Page (%d) = %d\n",i,*page_ptr++);
|
|
|
|
FORGETBLOCK(storage_ID);
|
|
|
|
return;
|
|
}
|
|
#endif /* !PROD */
|
|
#endif /* LIM */
|