1 /*******************************************************************************
3 * (C) Copyright Microsoft Corp. 1986
7 * MODULE: EMM40.C - EMM 4.0 functions code.
13 *******************************************************************************
15 * Date Version Description
16 * -------- -------- -------------------------------------------------------
17 * 02/25/87 0.00 Orignal
19 *******************************************************************************
20 * FUNCTIONAL DESCRIPTION
22 * Paged EMM Driver for the iAPX 386.
23 * Extra functions defined in the 4.0 spec required by Windows.
25 ******************************************************************************/
27 /******************************************************************************
29 ******************************************************************************/
31 /*#include "mem_mgr.h"*/
34 /******************************************************************************
35 EXTERNAL DATA STRUCTURES
36 ******************************************************************************/
39 * This is an array of handle pointers.
40 * page_index of zero means free
42 extern struct handle_ptr handle_table[];
43 extern Handle_Name Handle_Name_Table[]; /* Handle names */
44 extern unsigned short handle_table_size; /* number of entries */
45 extern unsigned short handle_count; /* active handle count */
49 * this array contains lists of indexes into the 386
50 * Page Table. Each list is pointed to by a handle
51 * table entry and is sequential/contiguous. This is
52 * so that maphandlepage doesn't have to scan a list
53 * for the specified entry.
55 extern unsigned short *emm_page; /* _emm_page array */
56 extern int free_count; /* current free count */
57 extern int total_pages; /* number being managed */
58 extern unsigned emmpt_start; /* next free entry in table */
62 * this array is a stack of available page table entries.
63 * each entry is an index into the pseudo page table
65 /*extern unsigned free_stack_count; /* number of entries */
68 * Current status of `HW'. The way this is handled is that
69 * when returning status to caller, normal status is reported
70 * via EMMstatus being moved into AX. Persistant errors
71 * (such as internal datastructure inconsistancies, etc) are
72 * placed in `EMMstatus' as HW failures. All other errors are
73 * transient in nature (out of memory, handles, ...) and are
74 * thus reported by directly setting AX. The EMMstatus variable
75 * is provided for expansion and is not currently being
76 * set to any other value.
78 extern unsigned short EMMstatus;
84 extern unsigned short emm40_info[5]; /* hardware information */
85 extern struct mappable_page mappable_pages[]; /* mappable segments
86 and corresponding pages */
87 extern short mappable_page_count; /* number of entries in above */
88 extern short page_frame_pages; /* pages in the page frame */
89 extern short physical_page_count; /* number of physical pages */
90 /*extern char VM1_cntxt_pages; /* pages in a VM1 context */
91 /*extern char VMn_cntxt_pages; /* pages in a VM context */
92 /*extern char VM1_cntxt_bytes; /* bytes in a VM1 context */
93 /*extern char VMn_cntxt_bytes; /* bytes in a VM context */
94 extern char cntxt_pages; /* pages in context */
95 extern char cntxt_bytes; /* bytes in context */
96 extern unsigned short PF_Base;
97 extern unsigned short VM1_EMM_Pages;
98 /*extern unsigned short VM1_EMM_Offset;*/
99 extern long page_frame_base[];
100 extern char EMM_MPindex[];
101 extern long OSEnabled; /* OS/E function flag */
102 extern long OSKey; /* Key for OS/E function */
104 /******************************************************************************
106 ******************************************************************************/
107 extern struct handle_ptr *valid_handle(); /* validate handle */
108 extern unsigned far *source_addr(); /* get DS:SI far ptr */
109 extern unsigned far *dest_addr(); /* get ES:DI far ptr */
110 extern unsigned wcopyb();
111 extern unsigned copyout();
112 extern unsigned short Avail_Pages();
115 /******************************************************************************
117 ******************************************************************************/
122 * bx -- new number of pages
125 * bx -- new number of pages
127 * Change the number of pages allocated to a handle.
129 * ISP 5/23/88 Updated for MEMM
133 #define handle ((unsigned short)regp->hregs.x.rdx)
135 register struct handle_ptr *hp;
136 struct handle_ptr *hp_save;
138 register unsigned n_pages;
139 register unsigned next;
141 if ( (hp = valid_handle(handle)) == NULL_HANDLE )
142 return; /* (error code already set) */
144 setAH((unsigned char)EMMstatus); /* Assume success */
145 new_size = regp->hregs.x.rbx;
146 if ( new_size == hp->page_count )
147 return; /* do nothing... */
149 if ( new_size > hp->page_count ) {
150 if ( new_size > total_pages ) {
151 setAH(NOT_ENOUGH_EXT_MEM);
154 n_pages = new_size - hp->page_count;
155 if ( n_pages > Avail_Pages() ) {
156 setAH(NOT_ENOUGH_FREE_MEM);
159 if ( hp->page_count == 0 )
160 next = hp->page_index = emmpt_start;
162 next = hp->page_index + hp->page_count;
163 hp->page_count = new_size;
164 if ( next != emmpt_start ) {
166 * Must shuffle emm_page array to make room
167 * for the extra pages. wcopyb correctly
168 * handles this case where the destination
169 * overlaps the source.
171 wcopyb(emm_page+next, emm_page+next+n_pages,
173 /* Now tell other handles where their pages went */
175 for ( hp = handle_table;
176 hp < &handle_table[handle_table_size]; hp++ )
177 if ( hp->page_index != NULL_PAGE &&
178 hp->page_index >= next )
179 hp->page_index += n_pages;
182 emmpt_start += n_pages;
183 if ( get_pages(n_pages, next) == NULL_PAGE) { /* strange failure */
184 setAH(NOT_ENOUGH_FREE_MEM);
185 new_size = hp->page_count - n_pages; /* as it was! */
187 goto shrink; /* and undo damage */
190 /* Shrinking - make handle point to unwanted pages */
192 hp->page_count -= new_size;
193 hp->page_index += new_size;
194 free_pages(hp); /* free space in emm_page array */
195 /* Undo damage to handle, the index was not changed */
196 hp->page_count = new_size;
197 hp->page_index -= new_size;
206 * An undefined or unsupported function.
208 * 05/10/88 ISP No update needed
212 setAH(INVALID_FUNCTION);
216 * Get Mappable Physical Address Array
219 * es:di -- destination
221 * cx -- number of mappable pages
226 * cx -- number of mappable pages
228 * Get the number of mappable pages and the segment address for each
231 * ISP 5/23/88 Updated for MEMM. u_ptr made into a far pointer.
233 GetMappablePAddrArray()
238 struct mappable_page *mp = mappable_pages;
240 n_pages = mappable_page_count;
242 if ( regp->hregs.h.ral == 0 ) {
244 u_ptr = dest_addr(); /* ES:DI */
245 for (i=0 ; i < 48 ; i++)
246 if (EMM_MPindex[i] != -1)
247 copyout(((struct mappable_page far *)u_ptr)++,
249 sizeof(struct mappable_page) );
251 } else if ( regp->hregs.h.ral != 1 ) {
252 setAH(INVALID_SUBFUNCTION);
256 setAH((unsigned char)EMMstatus);
260 * Get Expanded Memory Hardware Information
263 * es:di -- user array
265 * es:di[0] = raw page size in paragraphs
266 * es:di[2] = number of EXTRA fast register sets
267 * es:di[4] = number of bytes needed to save a context
268 * es:di[6] = number of settable DMA channels
273 * bx = number of free raw pages
274 * dx = total number of raw pages
276 * ISP 5/23/88 Updated for MEMM. Made u_ptr into far ptr.
283 if ( OSEnabled >= OS_DISABLED ) {
284 setAH(ACCESS_DENIED); /* Denied by operating system */
288 if ( regp->hregs.h.ral == 0 ) {
289 u_ptr = dest_addr(); /* ES:DI */
290 emm40_info[2] = (short)cntxt_bytes; /* update size */
291 copyout(u_ptr, emm40_info, sizeof(emm40_info));
292 setAH((unsigned char)EMMstatus);
293 } else if ( regp->hregs.h.ral == 1 ) {
294 GetUnallocatedPageCount(); /* Use existing code */
296 setAH(INVALID_SUBFUNCTION);
300 * GetSetHandleAttribute
305 * al == 0 -- volatile handles
310 * ah = 91h -- Feature not supported
315 * al == 0 -- Supports ONLY volatile handles
317 * 05/09/88 ISP No update needed
319 GetSetHandleAttribute()
321 #define handle ((unsigned short)regp->hregs.x.rdx)
323 if ( regp->hregs.h.ral == 0 ) {
324 if (valid_handle(handle) == NULL_HANDLE)
325 return; /* (error code already set) */
326 setAX(EMMstatus << 8); /* AL = 0 [volatile attribute] */
327 } else if ( regp->hregs.h.ral == 1 ) {
328 setAH(FEATURE_NOT_SUPPORTED);
329 } else if ( regp->hregs.h.ral == 2 ) {
330 setAX(EMMstatus << 8); /* AL = 0 [volatile attribute] */
332 setAH(INVALID_SUBFUNCTION);
343 * Subfunction 0 Gets the name of a given handle
344 * Subfunction 1 Sets a new name for handle
348 * es:di == Data area to copy handle name to
351 * [es:di] == Name of DX handle
355 * ds:si == new handle name
360 * ISP 5/23/88 Updated for MEMM. Name made into far *. Copyin routine used
361 * to copy name in into handle name table.
365 register unsigned short handle = ((unsigned short)regp->hregs.x.rdx);
366 register char far *Name;
368 /* Validate subfunction */
369 if ( (regp->hregs.h.ral != 0) && (regp->hregs.h.ral != 1) ) {
370 setAH(INVALID_SUBFUNCTION);
374 /* Validate handle */
376 if ( valid_handle(handle) == NULL_HANDLE )
377 return; /* (error code already set) */
379 /* Implement subfunctions 0 and 1 */
380 if ( regp->hregs.h.ral == 0 ) {
381 Name = (char far *)dest_addr(); /* ES:DI */
382 copyout(Name, Handle_Name_Table[handle & 0xFF], Handle_Name_Len);
383 setAH((unsigned char)EMMstatus);
384 } else if ( regp->hregs.h.ral == 1 ) {
385 GetHandleDirectory(); /* See if already there */
386 switch ( regp->hregs.h.rah ) {
387 case NAMED_HANDLE_NOT_FOUND:
389 case DUPLICATE_HANDLE_NAMES:
392 if ( handle == regp->hregs.x.rdx )
393 break; /* same handle, OK */
394 regp->hregs.x.rdx = handle;
395 setAH(DUPLICATE_HANDLE_NAMES);
398 Name = (char far *)source_addr();
399 copyin(Handle_Name_Table[handle & 0xFF], Name, Handle_Name_Len);
400 setAH((unsigned char)EMMstatus);
402 setAH(INVALID_SUBFUNCTION);
412 * Subfunction 0 Returns a directory of handles and handle names
413 * Subfunction 1 Returns the handle specified by the name at [ds:si]
417 * es:di == Data area to copy handle name to
419 * al == Number of entries in the handle_dir array
420 * [es:di] == Handle_Dir array
424 * [ds:si] == Handle name to locate
431 * bx == Total handles in system
433 * ISP 5/23/88 Updated for MEMM. nameaddress and dir_entry made into far *
434 * copyin routine used to copy name into local area for search.
438 char far *NameAddress;
439 register struct handle_ptr *hp;
440 struct Handle_Dir_Entry far *Dir_Entry;
441 unsigned short Handle_Num, Found;
443 * since all local variables are allocated on stack (SS seg)
444 * and DS and SS has grown apart (ie DS != SS),
445 * we need variables in DS seg (ie static variables) to pass
446 * to copyout(),copyin() and Names_Match() which expects those
447 * parameters that are near pointers to be in DS
451 static Handle_Name Name;
452 static unsigned short Real_Handle;
454 if ( regp->hregs.h.ral == 0 ) {
455 Dir_Entry = (struct Handle_Dir_Entry far *)dest_addr();
457 for (Handle_Num = 0; Handle_Num < handle_table_size; Handle_Num++) {
458 if ( hp->page_index != NULL_PAGE) {
459 Real_Handle = Handle_Num;
460 copyout(Dir_Entry, &Real_Handle, sizeof(short));
461 copyout(Dir_Entry->Dir_Handle_Name, Handle_Name_Table[Handle_Num], Handle_Name_Len);
464 } setAX((EMMstatus << 8) + handle_count);
465 } else if ( regp->hregs.h.ral == 1 ) {
466 NameAddress = (char far *)source_addr();
467 copyin(Name, NameAddress, Handle_Name_Len);
471 while ((Handle_Num < handle_table_size) && (Found < 2)) {
472 if ( hp->page_index != NULL_PAGE ) {
473 if (Names_Match(Name, Handle_Name_Table[Handle_Num])) {
475 Real_Handle = Handle_Num;
482 setAH((unsigned char)NAMED_HANDLE_NOT_FOUND);
486 setAH((unsigned char)EMMstatus);
489 setAH((unsigned char)DUPLICATE_HANDLE_NAMES);
492 } else if ( regp->hregs.h.ral == 2 ) {
493 setBX(handle_table_size);
494 setAH((unsigned char)EMMstatus);
496 setAH(INVALID_SUBFUNCTION);
502 * Prepare For Warm Boot
504 * Always ready to reboot the system so just return status = OK
511 * 05/09/88 ISP No update needed.
516 setAH((unsigned char)EMMstatus);
520 * Enable/Disable OS/E Function Set Functions
522 * Enable/Disable access to functions 26, 28 and 30
525 * AL = 0 Enable Functions
526 * AL = 1 Disable Functions
527 * AL = 2 Return Access Key
531 * BX, CX Access Key if successful
533 * 05/09/88 ISP Updated for MEMM. Removed check for pCurVMID
538 unsigned char function = regp->hregs.h.ral;
540 if ( function > 2 ) {
541 setAH(INVALID_SUBFUNCTION);
545 if ( OSEnabled == OS_IDLE ) { /* First invocation */
546 if ( function == 2 ) {
547 setAH(ACCESS_DENIED);
550 OSKey = Get_Key_Val(); /* Suitably random number */
551 regp->hregs.x.rbx = (short)OSKey;
552 regp->hregs.x.rcx = (short)(OSKey >> 16);
553 } else { /* Check Key */
554 if ( (short)OSKey != regp->hregs.x.rbx
555 || (short)(OSKey >> 16) != regp->hregs.x.rcx ) {
556 setAH(ACCESS_DENIED);
560 if ( function == 0 ) /* enable */
562 else if ( function == 1 ) /* disable */
564 else if ( function == 2 ) /* return key */
567 setAH((unsigned char)EMMstatus);