summaryrefslogtreecommitdiff
path: root/v4.0/src/MEMM/EMM/EMMFUNCT.C
diff options
context:
space:
mode:
Diffstat (limited to 'v4.0/src/MEMM/EMM/EMMFUNCT.C')
-rw-r--r--v4.0/src/MEMM/EMM/EMMFUNCT.C660
1 files changed, 660 insertions, 0 deletions
diff --git a/v4.0/src/MEMM/EMM/EMMFUNCT.C b/v4.0/src/MEMM/EMM/EMMFUNCT.C
new file mode 100644
index 0000000..7547536
--- /dev/null
+++ b/v4.0/src/MEMM/EMM/EMMFUNCT.C
@@ -0,0 +1,660 @@
1/*******************************************************************************
2 *
3 * (C) Copyright Microsoft Corp. 1986
4 *
5 * TITLE: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver
6 * EMMLIB.LIB - Expanded Memory Manager Library
7 *
8 * MODULE: EMMFUNCT.C - EMM functions code.
9 *
10 * VERSION: 0.10
11 *
12 * DATE: June 14,1986
13 *
14 *******************************************************************************
15 * CHANGE LOG
16 * Date Version Description
17 * -------- -------- -------------------------------------------------------
18 * 06/14/86 Changed status return to return only AH. And added
19 * PFlag to decide on selector versus segment on long
20 * address generation (SBP).
21 * 06/14/86 Moved save_current_map and restore_map to ASM (SBP).
22 * 06/15/86 Changed NULL_HANDLE to 0x0FFF (see emm.h) (SBP).
23 * 06/21/86 Moved MapHandlePage to ASM (SBP).
24 * Handle # passed to client has high byte = NOT (low byte)
25 * as in the Above Board (SBP).
26 * Valid_Handle -> ASM (SBP).
27 * 06/23/86 Make_Addr removed. source_addr and dest_addr added(SBP).
28 * 06/25/86 0.02 Dealloc checks for save area in use (SBP).
29 * 06/28/86 0.02 Name change from CEMM386 to CEMM (SBP).
30 * 06/29/86 0.02 Return after NOT_ENOUGH_FREE_MEM error in Allocate(SBP).
31 * 07/06/86 0.04 Changed _emm_page,_emm_free, & _pft386 to ptrs (SBP).
32 * 07/06/86 0.04 moved SavePageMap and RestorePageMap to .ASM (SBP).
33 * 07/08/86 0.04 moved GetSetPageMap to .ASM (SBP).
34 * 07/09/86 0.04 removed code which places handle # in _pft386
35 * entry (SBP).
36 * 07/09/86 0.05 fixed bug in deallocate (SBP).
37 * 05/09/88 0.10 modified for MEMM, modifications are indicated in
38 * individual routines (ISP).
39 *
40 *******************************************************************************
41 * FUNCTIONAL DESCRIPTION
42 *
43 * Paged EMM Driver for the iAPX 386.
44 *
45 * The basic concept is to use the 386's page tables to emulate
46 * the functions of an EMM board. There are several constraints
47 * that are a result of poor planning on the LIM specifiers part.
48 * - maximum of 64K instantaneously mapped. this will
49 * be faithfully emulated in this design
50 * - maximum of 8Mb of extended memory can be used.
51 * The actual reason for this is because each board
52 * can only support 128 16Kb pages and the limit of
53 * 4 Aboveboards implies 512 pages maximum. This will
54 * not be adhered to since the limit in unnecessary.
55 *
56 * The memory managed by this scheme can be discontiguous but
57 * a 16Kb EMM page can not be composed of discontiguous pieces.
58 * This is not necessary but does simplify the job of managing
59 * the memory.
60 *
61 * The LIM specification implies the existence of a partitioning
62 * of extended memory into `boards'. While this concept is not
63 * meaningfull in the 386 environment, a page to logical board
64 * mapping is provided to support some of the LIM specified
65 * functions:
66 * pages 0 to 127 map to board 0
67 * pages 128 to 255 map to board 1
68 * ...
69 * The pages in this case are logical pages and pages on the
70 * same logical board may actually reside on different physical
71 * boards. (In fact, if contiguous memory, a page could actually
72 * be split across 2 different boards.)
73 *
74 * A brief note on parameters:
75 * all parameters to EMM functions are passed in registers.
76 * on entry to the EMM dispatch code, the registers are pushed
77 * onto the stack. In order to access them, they are pointed
78 * to by a global variable (regp). Defines are used to name
79 * these parameters and make the code more readable.
80 *
81 * Definitions:
82 * Handle:
83 * 16 bit value that references a block of
84 * allocated memory. Internally, it is an index into a handle
85 * table. Externally, the high byte is the NOT of the low byte
86 * for compatibility with the Above Board EMM driver.
87 *
88 * EMM page:
89 * a 16Kb contiguous portion of memory, aligned on a
90 * 16Kb boundary in 8086 address space. In physical
91 * address space it can be aligned on a 4Kb boundary.
92 *
93 * page
94 * 386 page. 4Kb in size and 4Kb aligned in physical
95 * address space.
96 *
97 * far86 *
98 * An iAPX 86 style 32 bit pointer. It consists of
99 * a 16 bit offset in the low word and a base
100 * address in the high word.
101 *
102 * Logical page
103 * an EMM page allocated to a handle via allocatepages
104 * function. each such page has a logical page number.
105 *
106 * physical page frame
107 * the location in physical 8086 space that an EMM page
108 * gets mapped to. there are 4 such locations. they are
109 * contiguous starting at page_frame_base
110 *
111 * 386 page frame
112 * this is the physical page in 80386 physical
113 * address space. the address of a 386 page frame
114 * is the value placed in a 80386 page table entry's
115 * high 20 bits.
116 ******************************************************************************/
117
118/******************************************************************************
119 INCLUDE FILES
120 ******************************************************************************/
121#include "emm.h"
122
123
124/******************************************************************************
125 EXTERNAL DATA STRUCTURES
126 ******************************************************************************/
127/*
128 * I/O Map
129 * map_size
130 * this is an array of port addresses, 4 ports per
131 * emulated board. Each emulated board has up to
132 * 128 16Kb EMM pages assigned. The size of the table,
133 * the number of ports used, is map_size
134 * map_size = (<number of 386 pages>/(128*4))*4
135 */
136/*extern unsigned short iomap[]; */
137/*extern char map_size;*/
138
139/*
140 * map_known
141 * This flags is set whenever the user is given the I/O map
142 */
143/*extern char map_known; */
144
145/*
146 * page frame base
147 * this is a map of the linear addresses of the
148 * 4 16Kb EMM `physical' windows that the user
149 * accesses the EMM pages through. The entries
150 * of this array are far pointers into the page table.
151 * Thus, the address defined by page_frame_base[0]
152 * is the address of the long word that is the page
153 * table entry for the first EMM window. The reason for
154 * this obscurity is in speed of mapping -- it is used
155 * to directly obtain access to the entry to be programmed
156 */
157extern unsigned long page_frame_base[];
158
159/*
160 * save_map
161 * This is an array of structures that save the
162 * current mapping state. Size is dynamically determined.
163 */
164extern struct save_map save_map[];
165
166/*
167 * handle_table
168 * This is an array of handle pointers.
169 * page_index of zero means free
170 */
171extern struct handle_ptr handle_table[];
172extern Handle_Name Handle_Name_Table[];
173extern unsigned short handle_table_size; /* number of entries */
174extern unsigned short handle_count; /* active handle count */
175
176/*
177 * EMM Page table
178 * this array contains lists of indexes into the 386
179 * Page Frame Addresses (pft386). Each list is pointed to
180 * by a handle table entry and is sequential/contiguous.
181 * This is so that maphandlepage doesn't have to scan
182 * a list for the specified entry.
183 */
184extern unsigned short *emm_page; /* ptr to _emm_page array */
185extern unsigned short free_count; /* current free count */
186extern unsigned short total_pages; /* number being managed */
187extern unsigned short emmpt_start; /* next free entry in table */
188
189/*
190 * EMM free table
191 * this array is a stack of available page table entries.
192 * each entry is an index into pft386[].
193 */
194extern unsigned short *emm_free; /* ptr to _emm_free array */
195extern unsigned short free_top;
196
197/*
198 * Page frame table
199 * This array contains addresses of physical page frames
200 * for 386 pages. A page is refered to by an index into
201 * this array
202 */
203extern union pft386 *pft386; /* ptr to page frame table array */
204
205
206/*
207 * Current status of `HW'. The way this is handled is that
208 * when returning status to caller, normal status is reported
209 * via EMMstatus being moved into AX. Persistant errors
210 * (such as internal datastructure inconsistancies, etc) are
211 * placed in `EMMstatus' as HW failures. All other errors are
212 * transient in nature (out of memory, handles, ...) and are
213 * thus reported by directly setting AX. The EMMstatus variable
214 * is provided for expansion and is not currently being
215 * set to any other value.
216 */
217extern unsigned short EMMstatus;
218
219/*
220 * debug & such
221 */
222/*unsigned null_count = 0; /* number of attempts to map null pages */
223
224
225/******************************************************************************
226 EXTERNAL FUNCTIONS
227 ******************************************************************************/
228extern struct handle_ptr *valid_handle(); /* validate handle */
229extern unsigned far *source_addr(); /* get DS:SI far ptr */
230extern unsigned far *dest_addr(); /* get ES:DI far ptr */
231/*extern unsigned AutoUpdate(); /* update auto mode */
232extern unsigned wcopy();
233extern unsigned copyout();
234extern void reallocate();
235
236
237/******************************************************************************
238 ROUTINES
239 ******************************************************************************/
240
241/*
242 * Avail_Pages()
243 * returns: number of available emm pages
244 *
245 * 06/09/88 PC added the function
246 */
247unsigned short
248Avail_Pages()
249{
250 return(free_count) ;
251}
252
253/*
254 * get_pages(num,pto)
255 * num --- number of pages desired
256 * pto --- offset into emm_page array where the pages got are to be copied
257 * return value:
258 * emm_page[] index (pointer to list of allocated pages)
259 * NULL_PAGE means failure.
260 *
261 * 05/06/88 ISP Updated for MEMM removed handle as a parameter
262 */
263unsigned
264get_pages(num,pto)
265register unsigned num;
266register unsigned pto;
267{
268 register unsigned pg;
269 unsigned f_page;
270
271 if(free_count < num)
272 return(NULL_PAGE); /* not enough memory */
273 free_count -= num; /* adjust free count */
274 f_page = pg = pto;
275/* emmpt_start += num; */ /* new offset of avail area */
276
277 /*
278 * copy num elements from the emm_free array
279 * to the emm_page table array and update the
280 * corresponding page frame table entry (with a
281 * handle back pointer)
282 */
283 wcopy(emm_free+free_top, emm_page+pg, num);
284 free_top += num;
285 return(f_page);
286}
287
288
289/*
290 * free_pages(hp)
291 * hp --- handle whose pages should be deallocated
292 *
293 * Free the pages associated with the handle, but don't free the handle
294 *
295 * 05/09/88 ISP Pulled out from the deallocate page routine
296 */
297void
298free_pages(hp)
299register struct handle_ptr *hp;
300{
301 register unsigned next;
302 unsigned new_start;
303 unsigned h_size;
304
305 if (hp->page_count == 0) return ;
306 /*
307 * copy freed pages to top of free stack
308 */
309 free_top -= hp->page_count; /* free_top points to new top */
310 free_count += hp->page_count; /* bookkeeping */
311 wcopy(emm_page+hp->page_index, /* addr of first of list */
312 emm_free+free_top, /* addr of free space */
313 hp->page_count); /* # of pages to be freed */
314
315 /*
316 * now, the hard part. squeeze the newly created hole
317 * out of the emm_page array. this also requires updating the
318 * handle_table entry via the backlink in the pft386 array.
319 *
320 * do this in two phases:
321 * - copy the lower portion up to squeeze the hole out
322 * - readjust the handle table to point to the new
323 * location of the head element
324 */
325
326 next = hp->page_index + hp->page_count;
327 if(next == emmpt_start ) /* any lists below? */
328 {
329 /* no, all done */
330 emmpt_start -= hp->page_count;
331 return;
332 }
333
334 new_start = emmpt_start - hp->page_count;
335 wcopy(emm_page+next, /* 1st of rest of list */
336 emm_page+hp->page_index,/* addr of freed area */
337 emmpt_start-next); /* size of block of pages */
338
339 /*
340 * loop through the handle table entries, fixing up
341 * their page index fields
342 */
343 h_size = hp->page_count;
344 hp->page_count = 0; /* not really necessary */
345 for(hp=handle_table;hp < &handle_table[handle_table_size];hp++)
346 if((hp->page_index != NULL_PAGE) &&
347 (hp->page_index >= next) )
348 hp->page_index -= h_size;
349 emmpt_start = new_start; /* fix emmpt_start */
350}
351
352/*
353 * get status
354 * no parameters
355 *
356 * return current status of EMM subsystem
357 * (which, due to superior design is always just fine)
358 *
359 * 05/06/88 ISP No Update needed for MEMM
360 */
361GetStatus()
362{
363 setAH((unsigned char)EMMstatus); /* if we got here, we're OK */
364}
365
366
367/*
368 * get page frame address
369 * no parameters
370 *
371 * return the address of where the pages get mapped
372 * in user space
373 *
374 * 05/06/88 ISP Updated this routine from WIN386 sources.
375 */
376GetPageFrameAddress()
377{
378 extern unsigned short PF_Base;
379 extern unsigned short page_frame_pages;
380
381 /*
382 * return the 8086 style base address of
383 * the page frame base.
384 */
385 if ( page_frame_pages < 4 ) {
386 setAH(EMM_HW_MALFUNCTION); /* GET LOST!!! */
387 if ( PF_Base == 0xFFFF )
388 setBX(0xB000); /* In case error is ignored */
389 else
390 setBX(PF_Base); /* stunted page frame */
391 return;
392 }
393 setBX(PF_Base);
394 setAH((unsigned char)EMMstatus); /* OK return */
395}
396
397
398/*
399 * get unallocated page count
400 * no parameters
401 *
402 * returns:
403 * bx -- count of free pages
404 * dx -- total number of pages (free and allocated)
405 *
406 * 05/06/88 ISP No update needed for MEMM
407 */
408GetUnallocatedPageCount()
409{
410 setBX(free_count);
411 setDX(total_pages);
412 setAH((unsigned char)EMMstatus);
413}
414
415/*
416 * allocate pages
417 * parameters:
418 * n_pages (bx) -- allocation size request
419 *
420 * allocates the requested number of pages, creates
421 * a handle table entry and returns a handle to the
422 * allocated pages.
423 * calls AllocateRawPages
424 *
425 * 05/09/88 ISP updated for MEMM. Only handle value returned, not handle
426 * value with high byte as not of handle value. call to get
427 * pages also updated to remove handle parameter.
428 */
429AllocatePages()
430{
431#define n_pages ((unsigned)regp->hregs.x.rbx)
432 if(handle_count == handle_table_size){ /* no more handles? */
433 setAH(NO_MORE_HANDLES); /* nope */
434 return;
435 }
436
437 if(n_pages == 0) {
438 setAH(ZERO_PAGES);
439 return;
440 }
441
442 AllocateRawPages() ;
443}
444#undef n_pages
445
446/*
447 * allocate raw pages
448 * parameters:
449 * n_pages (bx) -- allocation size request
450 *
451 * allocates the requested number of raw pages,
452 * allocating 0 page is Okay
453 * calls allocated pages if non-zero.
454 *
455 * CREATED : 08/08/88 PLC
456 */
457AllocateRawPages()
458{
459#define n_pages ((unsigned)regp->hregs.x.rbx)
460 register unsigned handle; /* handle table index */
461 register struct handle_ptr *hp;
462
463 if(handle_count == handle_table_size){ /* no more handles? */
464 setAH(NO_MORE_HANDLES); /* nope */
465 return;
466 }
467
468 if(n_pages > total_pages) {
469 setAH(NOT_ENOUGH_EXT_MEM);
470 return;
471 }
472
473 /*
474 * loop through table to
475 * find available handle (page_index = NULL_PAGE)
476 */
477 hp = (struct handle_ptr *)handle_table;
478 for(handle=0;handle<handle_table_size;handle++,hp++)
479 if(hp->page_index == NULL_PAGE)
480 break; /* found a free one */
481 /*
482 * try and allocate pages
483 */
484 if((hp->page_index=get_pages(n_pages,emmpt_start)) != NULL_PAGE) {
485 emmpt_start += n_pages;
486 setAH((unsigned char)EMMstatus); /* got them! */
487 }
488 else {
489 setAH(NOT_ENOUGH_FREE_MEM); /* out of pages */
490 return;
491 }
492
493 hp->page_count=n_pages; /* set count */
494 handle_count++;
495 setDX(handle);
496
497/* AutoUpdate(); /* update status of Auto mode */
498
499}
500#undef n_pages
501
502/*
503 * deallocate pages
504 * parameters:
505 * dx -- handle
506 *
507 * free up the pages and handle table entry associated
508 * with this handle
509 *
510 * 05/09/88 ISP Updated for MEMM. Pulled out free_page routine and
511 * added support for handle name blanking.
512 */
513DeallocatePages()
514{
515#define handle ((unsigned)regp->hregs.x.rdx)
516 register struct handle_ptr *hp;
517 struct save_map *smp; /* save map table ptr */
518 long *Name ; /* points to handle name entry to clear */
519
520 if ( handle == 0 ) { /* Special handle, don't release */
521 int savbx = regp->hregs.x.rbx;
522 regp->hregs.x.rbx = 0;
523 ReallocatePages();
524 regp->hregs.x.rbx = savbx;
525 return;
526 }
527
528 if((hp=valid_handle(handle)) == NULL_HANDLE)
529 return; /* invalid handle, error code set */
530 /*
531 * check for save area in use for this handle
532 */
533 if( save_map[ (handle & 0x00FF) ].s_handle != (unsigned)NULL_HANDLE )
534 {
535 setAH(SAVED_PAGE_DEALLOC);
536 return;
537 }
538
539 free_pages(hp); /*free the pages associated with handle*/
540 hp->page_index = NULL_PAGE; /*and then free the handle*/
541 hp->page_count = 0; /*bookkeeping*/
542 Name = (long *)Handle_Name_Table[handle & 0xFF];
543 *(Name+1) = *(Name) = 0L; /* zero the eight byte name */
544 handle_count--; /* one less active handle */
545
546/* AutoUpdate(); /* update status of Auto mode */
547 setAH((unsigned char)EMMstatus); /* done */
548}
549#undef handle
550
551
552/*
553 * get emm version
554 * no parameters
555 *
556 * returns the version number of the emm driver
557 *
558 * 05/06/88 ISP No update needed for MEMM
559 */
560GetEMMVersion()
561{
562 setAX( (EMMstatus<<8) | EMM_VERSION );
563}
564
565/*
566 * Get EMM handle count
567 * no parameters
568 *
569 * return the number of active EMM handles
570 *
571 * 05/06/88 ISP No update needed for MEMM
572 */
573GetEMMHandleCount()
574{
575 setBX(handle_count);
576 setAH((unsigned char)EMMstatus);
577}
578
579/*
580 * Get EMM handle pages
581 * parameters:
582 * dx -- handle
583 *
584 * return the number of pages allocated to specified handle in BX
585 *
586 * 05/09/88 ISP No update needed for MEMM
587 */
588GetEMMHandlePages()
589{
590#define handle ((unsigned)regp->hregs.x.rdx)
591 register struct handle_ptr *hp;
592
593 if((hp=valid_handle(handle))==NULL_HANDLE) /*valid handle? */
594 return; /* no */
595 setBX(hp->page_count);
596 setAH((unsigned char)EMMstatus);
597}
598
599/*
600 * Get All EMM Handle Pages
601 * parameters:
602 * es:di -- userptr
603 *
604 * fill out array of handle/size pairs
605 *
606 * 05/09/88 ISP Updated for MEMM (just removed upper byte of handle)
607 */
608GetAllEMMHandlePages()
609{
610 unsigned far *u_ptr;
611 register struct handle_ptr *hp;
612 register unsigned h_index;
613
614 /*
615 * scan handle table and for each valid entry,
616 * copy handle and size to user array
617 */
618 u_ptr = dest_addr();
619
620 hp=handle_table;
621 for(h_index=0;h_index<handle_table_size;h_index++)
622 {
623 /* scan table for entries */
624 if(hp->page_index != NULL_PAGE) /* valid entry? */
625 {
626 *u_ptr++ = h_index; /* handle */
627 *u_ptr++ = hp->page_count; /*# of pgs for handle*/
628 }
629 hp++; /* next entry */
630 }
631 setBX(handle_count); /* bx <-- handle count */
632 setAH((unsigned char)EMMstatus);
633}
634
635/*
636 * Get Page Mapping Register I/O Port Array
637 * parameters:
638 es:di -- user array
639 *
640 * 05/09/88 ISP Function not supported
641 */
642GetPageMappingRegisterIOArray()
643{
644
645 setAH(INVALID_FUNCTION);
646}
647
648/*
649 * Get Logical to Physical Page Translation Array
650 * parameters:
651 * es:di -- pointer to user array
652 * dx ----- EMM handle
653 *
654 * 05/09/88 ISP Function not supported
655 */
656GetLogicalToPhysicalPageTrans()
657{
658 setAH(INVALID_FUNCTION);
659}
660 \ No newline at end of file