2 * Copyright (c) 1997 Helmut Wirth <hfwirth@ping.at>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice immediately at the beginning of the file, witout modification,
10 * this list of conditions, and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * $FreeBSD: src/usr.bin/doscmd/ems.c,v 1.3.2.2 2002/04/25 11:04:51 tg Exp $
29 * $DragonFly: src/usr.bin/doscmd/ems.c,v 1.4 2005/10/30 23:00:57 swildner Exp $
33 * EMS memory emulation
35 * To emulate Expanded Memory we use a DOS driver (emsdriv.sys) which
36 * routes calls to int 0x67 to this emulator routine. The main entry point
37 * is ems_entry(..). The emulator needs to be initialized before the first
38 * call. The first step of the initialization is done during program startup
39 * the second part is done during DOS boot, from a call of the DOS driver.
40 * The DOS driver is neccessary because DOS programs look for it to
41 * determine if EMS is available.
43 * To emulate a configurable amount of EMS memory we use a file created
44 * at startup with the size of the configured EMS memory. This file is
45 * mapped into the EMS window like any DOS memory manager would do, using
48 * The emulation follows the LIM EMS 4.0 standard. Not all functions of it
49 * are implemented yet. The "alter page map and jump" and "alter page map
50 * and call" functions are not implemented, because they are rather hard to
51 * do. (It would mean a call to the emulator executes a routine in EMS
52 * memory and returns to the emulator, the emulator switches the page map
53 * and then returns to the DOS program.) LINUX does not emulate this
54 * functions and I think they were very rarely used by DOS applications.
56 * Credits: To the writers of LINUX dosemu, I looked at their code
59 #include <sys/types.h>
60 #include <sys/param.h>
67 /* Will be configurable */
68 u_long ems_max_size
= EMS_MAXSIZE
* 1024;
69 u_long ems_frame_addr
= EMS_FRAME_ADDR
;
72 * Method for EMS: Allocate a mapfile with the size of EMS memory
73 * and map the needed part into the page frame
76 #define EMS_MAP_PATH "/var/tmp/" /* Use a big file system */
77 #define EMS_MAP_FILE "doscmd.XXXXXX"
78 static int mapfile_fd
= -1;
80 /* Pages are always 16 kB in size. The page frame is 64 kB, there are
81 * 4 positions (0..3) for a page to map in. The pages are numbered from 0 to
82 * the highest 16 kB page in the mapfile, depending on the EMS size
85 EMS_mapping_context ems_mapping_context
;
87 /* Handle and page management (see ems.h) */
89 /* The handle array. If the pointer is NULL, the handle is unallocated */
90 static EMS_handle
*ems_handle
[EMS_NUM_HANDLES
];
91 static u_long ems_alloc_handles
;
92 /* The active handle, if any */
93 static short active_handle
;
95 /* The page array. It is malloced at runtime, depending on the total
99 static EMS_page
*ems_page
= NULL
;
100 static u_long ems_total_pages
;
101 static u_long ems_alloc_pages
;
102 static u_long ems_free_pages
;
104 /* Local structure used for region copy and move operations */
109 short copytype
; /* Type of source and destination memory */
110 EMS_addr src_addr
; /* Combined pointer for source */
111 EMS_addr dst_addr
; /* Combined pointer for destination */
112 u_long rest_len
; /* Lenght to copy */
116 /* Local prototypes */
117 static int init_mapfile(void);
118 static void map_page(u_long
, u_char
, short, int);
119 static EMS_handle
*get_new_handle(long);
120 static void context_to_handle(short);
121 static long find_next_free_handle(void);
122 static short lookup_handle(Hname
*hp
);
123 static void allocate_pages_to_handle(u_short
, long);
124 static void allocate_handle(short, long);
125 static void reallocate_pages_to_handle(u_short
, long);
126 static void free_handle(short);
127 static void free_pages_of_handle(short);
128 static void restore_context(EMS_mapping_context
*);
129 static void save_context_to_dos(EMScontext
*);
130 static int check_saved_context(EMScontext
*);
131 static void *get_valid_pointer(u_short
, u_short
, u_long
);
132 static u_long
move_ems_to_conv(short, u_short
, u_short
, u_long
, u_long
);
133 static u_long
move_conv_to_ems(u_long
, u_short
, u_short
, u_short
, u_long
);
134 static u_long
move_ems_to_ems(u_short
, u_short
, u_short
, u_short
,
135 u_short
, u_short
, u_long
);
138 * EMS initialization routine: Return 1, if successful, return 0 if
139 * init problem or EMS disabled
147 if (ems_max_size
== 0)
149 if (init_mapfile() == 0)
152 bzero((void *)(&ems_handle
[0]), sizeof(ems_handle
));
153 ems_total_pages
= ems_max_size
/ EMS_PAGESIZE
;
155 ems_free_pages
= ems_total_pages
;
156 ems_alloc_handles
= 0;
158 /* Malloc the page array */
159 ems_page
= (EMS_page
*)malloc(sizeof(EMS_page
) * ems_total_pages
);
160 if (ems_page
== NULL
) {
161 debug(D_ALWAYS
, "Could not malloc page array, EMS disabled\n");
167 for (i
= 0; i
< ems_total_pages
; i
++) {
168 ems_page
[i
].handle
= 0;
169 ems_page
[i
].status
= EMS_FREE
;
171 debug(D_EMS
, "EMS: Emulation init OK.\n");
176 /* Main entry point */
179 ems_entry(regcontext_t
*REGS
)
182 * If EMS is not enabled, the DOS ems.exe module should not have
183 * been loaded. If it is loaded anyway, report software malfunction
185 if (ems_max_size
== 0) {
186 R_AH
= EMS_SW_MALFUNC
;
187 debug(D_EMS
, "EMS emulation not enabled\n");
193 case GET_MANAGER_STATUS
:
194 debug(D_EMS
, "EMS: Get manager status\n");
198 case GET_PAGE_FRAME_SEGMENT
:
199 debug(D_EMS
, "EMS: Get page frame segment\n");
200 R_BX
= ems_frame_addr
>> 4;
204 case GET_PAGE_COUNTS
:
205 R_BX
= ems_total_pages
- ems_alloc_pages
;
206 R_DX
= ems_total_pages
;
207 debug(D_EMS
, "EMS: Get page count: Returned total=%d, free=%d\n",
212 case GET_HANDLE_AND_ALLOCATE
:
218 debug(D_EMS
, "EMS: Get handle and allocate %d pages: ", npages
);
220 /* Enough handles? */
221 if ((handle
= find_next_free_handle()) < 0) {
222 debug(D_EMS
,"Return error:No handles\n");
223 R_AH
= EMS_OUT_OF_HANDLES
;
226 /* Enough memory for this request ? */
227 if (npages
> ems_free_pages
) {
228 debug(D_EMS
,"Return error:Request too big\n");
229 R_AH
= EMS_OUT_OF_LOG
;
232 if (npages
> ems_total_pages
) {
233 debug(D_EMS
,"Return error:Request too big\n");
234 R_AH
= EMS_OUT_OF_PHYS
;
237 /* Not allowed to allocate zero pages with this function */
239 debug(D_EMS
,"Return error:Cannot allocate 0 pages\n");
240 R_AH
= EMS_ZERO_PAGES
;
243 /* Allocate the handle */
244 allocate_handle(handle
, npages
);
246 /* Allocate the pages */
247 allocate_pages_to_handle(handle
, npages
);
250 debug(D_EMS
,"Return success:Handle = %d\n", handle
);
257 u_short hpagenum
, spagenum
;
260 debug(D_EMS
, "EMS: Map/Unmap handle=%d, pos=%d, pagenum=%d ",
265 debug(D_EMS
, "invalid position\n");
270 /* This succeeds without a valid handle ! */
271 if (hpagenum
== 0xffff) {
273 map_page(0, position
, handle
, 1);
274 debug(D_EMS
, "(unmap only) success\n");
278 if (handle
> 255 || handle
== 0 || ems_handle
[handle
] == NULL
) {
279 R_AH
= EMS_INV_HANDLE
;
280 debug(D_EMS
, "invalid handle\n");
283 if (hpagenum
>= ems_handle
[handle
]->npages
) {
284 R_AH
= EMS_LOGPAGE_TOOBIG
;
285 debug(D_EMS
, "invalid pagenumber\n");
288 spagenum
= ems_handle
[handle
]->pagenum
[hpagenum
];
289 map_page(spagenum
, position
, handle
, 0);
290 debug(D_EMS
, "success\n");
295 case DEALLOCATE_HANDLE
:
301 debug(D_EMS
, "EMS: Deallocate handle %d\n", handle
);
302 if (handle
> 255 || ems_handle
[handle
] == NULL
) {
303 R_AH
= EMS_INV_HANDLE
;
306 /* Mapping context saved ? */
307 if (ems_handle
[handle
]->mcontext
!= NULL
) {
308 R_AH
= EMS_SAVED_MAP
;
312 free_pages_of_handle(handle
);
318 case GET_EMM_VERSION
:
319 debug(D_EMS
, "EMS: Get version\n");
328 debug(D_EMS
, "EMS: Save page map\n");
330 if (handle
> 255 || handle
== 0 || ems_handle
[handle
] == NULL
) {
331 R_AH
= EMS_INV_HANDLE
;
334 if (ems_handle
[handle
]->mcontext
!= NULL
) {
335 /* There is already a context saved */
336 if (memcmp((void *)ems_handle
[handle
]->mcontext
,
337 (void *)&ems_mapping_context
,
338 sizeof(EMS_mapping_context
)) == 0)
339 R_AH
= EMS_ALREADY_SAVED
;
341 R_AH
= EMS_NO_ROOM_TO_SAVE
;
344 context_to_handle(handle
);
349 case RESTORE_PAGE_MAP
:
353 debug(D_EMS
, "EMS: Restore page map\n");
355 if (handle
> 255 || handle
== 0 || ems_handle
[handle
] == NULL
) {
356 R_AH
= EMS_INV_HANDLE
;
359 if (ems_handle
[handle
]->mcontext
== NULL
) {
360 R_AH
= EMS_NO_SAVED_CONTEXT
;
363 restore_context(ems_handle
[handle
]->mcontext
);
364 free((void *)ems_handle
[handle
]->mcontext
);
365 ems_handle
[handle
]->mcontext
= NULL
;
372 debug(D_ALWAYS
, "Reserved function called: %02x\n", R_AH
);
373 R_AH
= EMS_FUNC_NOSUP
;
376 case GET_HANDLE_COUNT
:
377 debug(D_EMS
, "EMS: Get handle count\n");
378 R_BX
= ems_alloc_handles
+ 1;
382 case GET_PAGES_OWNED
:
386 debug(D_EMS
, "EMS: Get pages owned\n");
389 if (handle
> 255 || ems_handle
[handle
] == NULL
) {
390 R_AH
= EMS_INV_HANDLE
;
396 R_BX
= ems_handle
[handle
]->npages
;
401 case GET_PAGES_FOR_ALL
:
407 debug(D_EMS
, "EMS: Get pages for all\n");
408 /* Get the address passed from DOS app */
409 ehp
= (EMShandlepage
*)get_valid_pointer(R_ES
, R_DI
,
410 sizeof(EMShandlepage
) * ems_alloc_handles
);
412 R_AH
= EMS_SW_MALFUNC
;
416 R_BX
= ems_alloc_handles
;
418 for (i
= 0; i
< 255; i
++) {
419 if (ems_handle
[i
] != NULL
) {
420 if (safecount
> (ems_alloc_handles
+1))
421 fatal("EMS: ems_alloc_handles is wrong, "
422 "cannot continue\n");
424 ehp
->npages
= ems_handle
[i
]->npages
;
434 /* This function is a nuisance. It was invented to save time and
435 * memory, but in our case it is useless. We have to support it
436 * but we use the same save memory as for the page map function.
437 * It uses only 20 bytes anyway. We store/restore the entire mapping
439 case PAGE_MAP_PARTIAL
:
442 EMScontext
*src
, *dest
;
444 debug(D_EMS
, "EMS: Page map ");
446 if (R_AH
== PAGE_MAP_PARTIAL
) {
447 debug(D_EMS
, "partial ");
448 /* Page map partial has slightly different subfunctions
449 * GET_SET does not exist and is GET_SIZE in this case
451 if (subfunction
== GET_SET
)
452 subfunction
= GET_SIZE
;
458 debug(D_EMS
, "get\n");
459 /* Get the address passed from DOS app */
460 dest
= (EMScontext
*)get_valid_pointer(R_ES
, R_DI
,
463 R_AH
= EMS_SW_MALFUNC
;
466 save_context_to_dos(dest
);
472 debug(D_EMS
, "set\n");
473 src
= (EMScontext
*)get_valid_pointer(R_DS
, R_SI
,
476 R_AH
= EMS_SW_MALFUNC
;
479 if (check_saved_context(src
) == 0) {
480 R_AH
= EMS_SAVED_CONTEXT_BAD
;
483 restore_context(&src
->ems_saved_context
);
489 debug(D_EMS
, "get/set\n");
490 dest
= (EMScontext
*)get_valid_pointer(R_ES
, R_DI
,
493 R_AH
= EMS_SW_MALFUNC
;
496 save_context_to_dos(dest
);
497 src
= (EMScontext
*)get_valid_pointer(R_DS
, R_SI
,
500 R_AH
= EMS_SW_MALFUNC
;
503 if (check_saved_context(src
) == 0) {
504 R_AH
= EMS_SAVED_CONTEXT_BAD
;
507 restore_context(&src
->ems_saved_context
);
512 debug(D_EMS
, "get size\n");
513 R_AL
= (sizeof(EMScontext
) + 1) & 0xfe;
517 debug(D_EMS
, "invalid subfunction\n");
518 R_AH
= EMS_INVALID_SUB
;
524 case MAP_UNMAP_MULTI_HANDLE
:
527 u_short hpagenum
, spagenum
;
533 debug(D_EMS
, "EMS: Map/Unmap multiple ");
535 if ((n_entry
= R_CX
) > 3) {
539 /* This is valid according to the LIM EMS 4.0 spec */
546 if (handle
> 255 || handle
== 0 || ems_handle
[handle
] == NULL
) {
547 R_AH
= EMS_INV_HANDLE
;
551 mp
= (EMSmapunmap
*)get_valid_pointer(R_DS
, R_SI
,
552 sizeof(EMSmapunmap
) * n_entry
);
554 R_AH
= EMS_SW_MALFUNC
;
559 /* Walk through the table and map/unmap */
560 for (i
= 0; i
< n_entry
; i
++) {
562 /* Method is in R_AL */
564 debug(D_EMS
, "phys page method\n");
571 } else if (R_AL
== 1) {
572 /* Compute position from segment address */
575 debug(D_EMS
, "segment method\n");
577 p_seg
-= ems_frame_addr
;
578 p_seg
/= EMS_PAGESIZE
;
586 debug(D_EMS
, "invalid subfunction\n");
587 R_AH
= EMS_INVALID_SUB
;
592 if (hpagenum
== 0xffff) {
594 map_page(0, position
, handle
, 1);
597 if (hpagenum
>= ems_handle
[handle
]->npages
) {
598 R_AH
= EMS_LOGPAGE_TOOBIG
;
601 spagenum
= ems_handle
[handle
]->pagenum
[hpagenum
];
602 map_page(spagenum
, position
, handle
, 0);
612 debug(D_EMS
, "EMS: Realloc pages ");
615 if (handle
> 255 || handle
== 0 || ems_handle
[handle
] == NULL
) {
616 R_AH
= EMS_INV_HANDLE
;
617 debug(D_EMS
, "invalid handle\n");
621 debug(D_EMS
, "changed from %ld to %ld pages\n",
622 ems_handle
[handle
]->npages
, newpages
);
624 /* Case 1: Realloc to zero pages */
626 free_pages_of_handle(handle
);
630 /* Case 2: New allocation is equal to allocated number */
631 if (newpages
== ems_handle
[handle
]->npages
) {
635 /* Case 3: Reallocate to bigger and smaller sizes */
636 if (newpages
> ems_handle
[handle
]->npages
) {
637 if (newpages
> ems_free_pages
) {
638 R_AH
= EMS_OUT_OF_LOG
;
641 if (newpages
> ems_total_pages
) {
642 R_AH
= EMS_OUT_OF_PHYS
;
646 reallocate_pages_to_handle(handle
, newpages
);
651 /* We do not support nonvolatile pages */
652 case HANDLE_ATTRIBUTES
:
653 debug(D_EMS
, "Handle attributes called\n");
657 R_AH
= EMS_FEAT_NOSUP
;
659 case HANDLE_CAPABILITY
:
660 R_AL
= 0; /* Volatile only */
664 R_AH
= EMS_FUNC_NOSUP
;
675 if (handle
> 255 || handle
== 0 || ems_handle
[handle
] == NULL
) {
676 R_AH
= EMS_INV_HANDLE
;
677 debug(D_EMS
, "invalid handle\n");
682 if ((hp
= (Hname
*)get_valid_pointer(R_ES
, R_DI
, 8))
684 R_AH
= EMS_SW_MALFUNC
;
687 *hp
= ems_handle
[handle
]->hname
;
692 if ((hp
= (Hname
*)get_valid_pointer(R_DS
, R_SI
, 8))
694 R_AH
= EMS_SW_MALFUNC
;
697 /* If the handle name is not 0, it may not exist */
698 if ((hp
->ul_hn
[0] | hp
->ul_hn
[1]) != 0) {
699 if (lookup_handle(hp
) == 0) {
700 ems_handle
[handle
]->hname
= *hp
;
703 R_AH
= EMS_NAME_EXISTS
;
707 /* Name is deleted (set to zeros) */
708 ems_handle
[handle
]->hname
= *hp
;
714 R_AH
= EMS_FUNC_NOSUP
;
720 case HANDLE_DIRECTORY
:
729 hdp
= (EMShandledir
*)get_valid_pointer(R_ES
, R_DI
,
730 sizeof(EMShandledir
) * ems_alloc_handles
);
732 R_AH
= EMS_SW_MALFUNC
;
735 for (i
= 0; i
< EMS_NUM_HANDLES
; i
++) {
736 if (ems_handle
[i
] != NULL
) {
738 hdp
->name
= ems_handle
[i
]->hname
;
745 hp
= (Hname
*)get_valid_pointer(R_DS
, R_SI
, 8);
747 R_AH
= EMS_SW_MALFUNC
;
750 /* Cannot search for NULL handle name */
751 if ((hp
->ul_hn
[0] | hp
->ul_hn
[1]) != 0) {
752 R_AH
= EMS_NAME_EXISTS
;
755 if ((handle
= lookup_handle(hp
)) == 0) {
756 R_AH
= EMS_HNAME_NOT_FOUND
;
763 case GET_TOTAL_HANDLES
:
765 R_BX
= EMS_NUM_HANDLES
; /* Includes OS handle */
769 R_AH
= EMS_FUNC_NOSUP
;
776 /* I do not know if we need this. LINUX emulation leaves it out
777 * so I leave it out too for now.
779 case ALTER_PAGEMAP_JUMP
:
780 debug(D_ALWAYS
, "Alter pagemap and jump used!\n");
781 R_AH
= EMS_FUNC_NOSUP
;
783 case ALTER_PAGEMAP_CALL
:
784 debug(D_ALWAYS
, "Alter pagemap and call used!\n");
785 R_AH
= EMS_FUNC_NOSUP
;
789 case MOVE_MEMORY_REGION
:
792 u_long src_addr
, dst_addr
;
793 u_short src_handle
, dst_handle
;
795 if (R_AL
== EXCHANGE
)
796 debug(D_EMS
, "EMS: Exchange memory region ");
798 debug(D_EMS
, "EMS: Move memory region ");
800 emvp
= (EMSmovemem
*)get_valid_pointer(R_DS
, R_SI
,
803 debug(D_EMS
, "Invalid structure pointer\n");
804 R_AH
= EMS_SW_MALFUNC
;
807 /* Zero length is not an error */
808 if (emvp
->length
== 0) {
809 debug(D_EMS
, "Zero length\n");
814 if (emvp
->src_type
== EMS_MOVE_CONV
) {
815 /* Conventional memory source */
816 src_addr
= MAKEPTR(emvp
->src_seg
, emvp
->src_offset
);
817 /* May not exceed conventional memory */
818 if ((src_addr
+ emvp
->length
) > 640 * 1024) {
819 R_AH
= EMS_SW_MALFUNC
;
823 /* Check the handle */
824 src_handle
= emvp
->src_handle
;
825 if (src_handle
> 255 || src_handle
== 0 ||
826 ems_handle
[src_handle
] == NULL
) {
827 R_AH
= EMS_INV_HANDLE
;
828 debug(D_EMS
, "invalid source handle\n");
831 /* Offset may not exceed page size */
832 if (emvp
->src_offset
>= (16 * 1024)) {
833 R_AH
= EMS_PAGEOFFSET
;
834 debug(D_EMS
, "source page offset too big\n");
839 if (emvp
->dst_type
== EMS_MOVE_CONV
) {
840 /* Conventional memory source */
841 dst_addr
= MAKEPTR(emvp
->dst_seg
, emvp
->dst_offset
);
842 /* May not exceed conventional memory */
843 if ((dst_addr
+ emvp
->length
) > 640 * 1024) {
844 R_AH
= EMS_SW_MALFUNC
;
848 /* Check the handle */
849 dst_handle
= emvp
->dst_handle
;
850 if (dst_handle
> 255 || dst_handle
== 0 ||
851 ems_handle
[dst_handle
] == NULL
) {
852 R_AH
= EMS_INV_HANDLE
;
853 debug(D_EMS
, "invalid destination handle\n");
856 /* Offset may not exceed page size */
857 if (emvp
->dst_offset
>= (16 * 1024)) {
858 R_AH
= EMS_PAGEOFFSET
;
859 debug(D_EMS
, "destination page offset too big\n");
865 /* If it is conventional memory only, do it */
866 if (emvp
->src_type
== EMS_MOVE_CONV
&&
867 emvp
->dst_type
== EMS_MOVE_CONV
) {
868 memmove((void *)dst_addr
, (void *)src_addr
,
869 (size_t) emvp
->length
);
870 debug(D_EMS
, "conventional to conventional memory done\n");
874 if (emvp
->src_type
== EMS_MOVE_EMS
&&
875 emvp
->dst_type
== EMS_MOVE_CONV
)
876 R_AH
= move_ems_to_conv(src_handle
, emvp
->src_seg
,
877 emvp
->src_offset
, dst_addr
, emvp
->length
);
878 else if (emvp
->src_type
== EMS_MOVE_CONV
&&
879 emvp
->dst_type
== EMS_MOVE_EMS
)
880 R_AH
= move_conv_to_ems(src_addr
, dst_handle
,
881 emvp
->dst_seg
, emvp
->dst_offset
, emvp
->length
);
883 R_AH
= move_ems_to_ems(src_handle
, emvp
->src_seg
,
884 emvp
->src_offset
, dst_handle
, emvp
->dst_seg
,
885 emvp
->dst_offset
, emvp
->length
);
886 debug(D_EMS
, " done\n");
889 /* exchange memory region */
891 /* We need a scratch area for the exchange */
893 if ((buffer
= malloc(emvp
->length
)) == NULL
)
894 fatal("EMS: Could not malloc scratch area for exchange");
896 /* If it is conventional memory only, do it */
897 if (emvp
->src_type
== EMS_MOVE_CONV
&&
898 emvp
->dst_type
== EMS_MOVE_CONV
) {
899 /* destination -> buffer */
900 memmove(buffer
, (void *)dst_addr
, (size_t) emvp
->length
);
901 /* Source -> destination */
902 memmove((void *)dst_addr
, (void *)src_addr
,
903 (size_t) emvp
->length
);
904 /* Buffer -> source */
905 memmove((void *)src_addr
, buffer
, (size_t) emvp
->length
);
907 debug(D_EMS
, "conventional to conventional memory done\n");
912 /* Exchange EMS with conventional */
913 if (emvp
->src_type
== EMS_MOVE_EMS
&&
914 emvp
->dst_type
== EMS_MOVE_CONV
) {
915 /* Destination -> buffer */
916 memmove(buffer
, (void *)dst_addr
, (size_t) emvp
->length
);
917 /* Source -> destination */
918 R_AH
= move_ems_to_conv(src_handle
, emvp
->src_seg
,
919 emvp
->src_offset
, dst_addr
, emvp
->length
);
920 if (R_AH
!= EMS_SUCCESS
) {
924 /* Buffer -> source */
925 R_AH
= move_conv_to_ems((u_long
)buffer
, src_handle
,
926 emvp
->src_seg
, emvp
->src_offset
, emvp
->length
);
928 /* Exchange conventional with EMS */
929 } else if (emvp
->src_type
== EMS_MOVE_CONV
&&
930 emvp
->dst_type
== EMS_MOVE_EMS
) {
931 /* Destination -> buffer */
932 R_AH
= move_ems_to_conv(dst_handle
, emvp
->dst_seg
,
933 emvp
->dst_offset
, (u_long
)buffer
, emvp
->length
);
934 if (R_AH
!= EMS_SUCCESS
) {
938 /* Source -> destination */
939 R_AH
= move_conv_to_ems((u_long
)buffer
, dst_handle
,
940 emvp
->dst_seg
, emvp
->dst_offset
, emvp
->length
);
941 /* Buffer -> source */
942 memmove(buffer
, (void *)src_addr
, (size_t) emvp
->length
);
944 /* Exchange EMS with EMS */
946 /* Destination -> buffer */
947 R_AH
= move_ems_to_conv(dst_handle
, emvp
->dst_seg
,
948 emvp
->dst_offset
, (u_long
)buffer
, emvp
->length
);
949 if (R_AH
!= EMS_SUCCESS
) {
953 /* Source -> destination */
954 R_AH
= move_ems_to_ems(src_handle
, emvp
->src_seg
,
955 emvp
->src_offset
, dst_handle
, emvp
->dst_seg
,
956 emvp
->dst_offset
, emvp
->length
);
957 if (R_AH
!= EMS_SUCCESS
) {
961 /* Buffer -> source */
962 R_AH
= move_conv_to_ems((u_long
)buffer
, src_handle
,
963 emvp
->src_seg
, emvp
->src_offset
, emvp
->length
);
967 debug(D_EMS
, " done\n");
971 case GET_MAPPABLE_PHYS_ADDR
:
980 eadp
= (EMSaddrarray
*)get_valid_pointer(R_ES
, R_DI
,
981 sizeof(EMSaddrarray
) * 4);
983 R_AH
= EMS_SW_MALFUNC
;
986 for (i
= 0, seg
= (ems_frame_addr
>> 4); i
< 4; i
++) {
995 case GET_ARRAY_ENTRIES
:
996 /* There are always 4 positions, 4*16kB = 64kB */
1001 R_AH
= EMS_FUNC_NOSUP
;
1007 /* This is an OS function in the LIM EMS 4.0 standard: It is
1008 * usable only by an OS and its use can be disabled for all other
1009 * programs. I think we do not need to support it. It is not
1010 * implemented and it reports "disabled" to any caller.
1012 case GET_HW_CONFIGURATION
:
1013 R_AH
= EMS_FUNCTION_DISABLED
;
1016 /* This function is a little different, it was defined with
1017 * LIM EMS 4.0: It is allowed to allocate zero pages and raw
1018 * page size (i.e. page size != 16kB) is supported. We have
1019 * only 16kB pages, so the second difference does not matter.
1021 case ALLOCATE_PAGES
:
1027 debug(D_EMS
, "EMS: Get handle and allocate %d pages: ", npages
);
1029 /* Enough handles? */
1030 if ((handle
= find_next_free_handle()) < 0) {
1031 debug(D_EMS
,"Return error:No handles\n");
1032 R_AH
= EMS_OUT_OF_HANDLES
;
1035 /* Enough memory for this request ? */
1036 if (npages
> ems_free_pages
) {
1037 debug(D_EMS
,"Return error:Request too big\n");
1038 R_AH
= EMS_OUT_OF_LOG
;
1041 if (npages
> ems_total_pages
) {
1042 debug(D_EMS
,"Return error:Request too big\n");
1043 R_AH
= EMS_OUT_OF_PHYS
;
1047 /* Allocate the handle */
1048 allocate_handle(handle
, npages
);
1050 /* Allocate the pages */
1051 allocate_pages_to_handle(handle
, npages
);
1054 debug(D_EMS
,"Return success:Handle = %d\n", handle
);
1058 /* This is an OS function in the LIM EMS 4.0 standard: It is
1059 * usable only by an OS and its use can be disabled for all other
1060 * programs. I think we do not need to support it. It is not
1061 * implemented and it reports "disabled" to any caller.
1063 case ALTERNATE_MAP_REGISTER
:
1064 R_AH
= EMS_FUNCTION_DISABLED
;
1067 /* We cannot support that ! */
1068 case PREPARE_WARMBOOT
:
1069 R_AH
= EMS_FUNC_NOSUP
;
1072 case OS_FUNCTION_SET
:
1073 R_AH
= EMS_FUNCTION_DISABLED
;
1077 debug(D_ALWAYS
, "EMS: Unknown function called: %02x\n", R_AH
);
1078 R_AH
= EMS_FUNC_NOSUP
;
1083 /* Initialize the EMS memory: Return 1 on success, 0 on failure */
1092 if (ems_max_size
== 0)
1094 strcpy(path
, EMS_MAP_PATH
);
1095 strcat(path
, EMS_MAP_FILE
);
1097 mfd
= mkstemp(path
);
1100 debug(D_ALWAYS
, "Could not create EMS mapfile, ");
1104 mapfile_fd
= squirrel_fd(mfd
);
1106 if (lseek(mapfile_fd
, (off_t
)(ems_max_size
- 1), 0) < 0) {
1107 debug(D_ALWAYS
, "Could not seek into EMS mapfile, ");
1110 if (write(mapfile_fd
, "", 1) < 0) {
1111 debug(D_ALWAYS
, "Could not write to EMS mapfile, ");
1114 /* Unmap the entire page frame */
1115 if (munmap((caddr_t
)ems_frame_addr
, 64 * 1024) < 0) {
1116 debug(D_ALWAYS
, "Could not unmap EMS page frame, ");
1119 /* DOS programs will access the page frame without allocating
1120 * pages first. Microsoft diagnose MSD.EXE does this, for example
1121 * We need to have memory here to avoid segmentation violation
1123 if (mmap((caddr_t
)ems_frame_addr
, 64 * 1024,
1124 PROT_EXEC
| PROT_READ
| PROT_WRITE
,
1125 MAP_ANON
| MAP_FIXED
| MAP_SHARED
,
1126 -1, 0) == MAP_FAILED
) {
1127 debug(D_ALWAYS
, "Could not map EMS page frame, ");
1130 bzero((void *)&ems_mapping_context
, sizeof(EMS_mapping_context
));
1134 debug(D_ALWAYS
, "EMS disabled\n");
1140 /* Map/Unmap pages into one of four positions in the frame segment */
1143 map_page(u_long pagenum
, u_char position
, short handle
, int unmaponly
)
1150 fatal("EMS: Internal error: Mapping position\n");
1152 map_addr
= (caddr_t
)(ems_frame_addr
+ (1024 * 16 * (u_long
)position
));
1154 file_offs
= (off_t
)(pagenum
* 16 * 1024);
1156 if (ems_mapping_context
.pos_mapped
[position
]) {
1157 if (munmap(map_addr
, len
) < 0) {
1158 fatal("EMS unmapping error: %s\nCannot recover\n",
1161 ems_page
[ems_mapping_context
.pos_pagenum
[position
]].status
1163 ems_mapping_context
.pos_mapped
[position
] = 0;
1164 ems_mapping_context
.handle
[position
] = 0;
1167 /* DOS programs will access the page frame without allocating
1168 * pages first. Microsoft diagnose MSD.EXE does this, for example
1169 * We need to have memory here to avoid segmentation violation
1171 if (mmap((caddr_t
)ems_frame_addr
, 64 * 1024,
1172 PROT_EXEC
| PROT_READ
| PROT_WRITE
,
1173 MAP_ANON
| MAP_FIXED
| MAP_SHARED
,
1174 -1, 0) == MAP_FAILED
)
1175 fatal("Could not map EMS page frame during unmap only\n");
1178 if (mmap(map_addr
, len
,
1179 PROT_EXEC
| PROT_READ
| PROT_WRITE
,
1180 MAP_FILE
| MAP_FIXED
| MAP_SHARED
,
1181 mapfile_fd
, file_offs
) == MAP_FAILED
) {
1182 fatal("EMS mapping error: %s\nCannot recover\n", strerror(errno
));
1184 ems_mapping_context
.pos_mapped
[position
] = 1;
1185 ems_mapping_context
.pos_pagenum
[position
] = pagenum
;
1186 ems_mapping_context
.handle
[position
] = handle
;
1187 ems_page
[pagenum
].status
|= EMS_MAPPED
;
1190 /* Get a pointer from VM86 app, check it and return it. This returns NULL
1191 * if the pointer is not valid. We can check only for very limited
1192 * criteria: The pointer and the area defined by size may not point to
1193 * memory over 1MB and it may not may to addresses under 1kB, because there
1194 * is the VM86 interrupt table.
1197 get_valid_pointer(u_short seg
, u_short offs
, u_long size
)
1200 addr
= MAKEPTR(seg
, offs
);
1202 if ((addr
+ size
) >= (1024 * 1024) || addr
< 1024)
1205 return (void *)addr
;
1208 /* Malloc a new handle */
1210 get_new_handle(long npages
)
1213 size_t dynsize
= sizeof(EMS_handle
) + sizeof(short) * npages
;
1215 if ((ehp
= calloc(1, dynsize
)) == NULL
)
1216 fatal("Cannot malloc EMS handle, cannot continue\n");
1220 /* Allocate a mapping context to a handle */
1222 context_to_handle(short handle
)
1224 EMS_mapping_context
*emc
;
1226 if (ems_handle
[handle
] == NULL
)
1227 fatal("EMS context_to_handle called with invalid handle\n");
1228 if ((emc
= calloc(1, sizeof(EMS_mapping_context
))) == NULL
)
1229 fatal("EMS Cannot malloc mapping context, cannot continue\n");
1230 ems_handle
[handle
]->mcontext
= emc
;
1231 memmove((void *)emc
, (void *)&ems_mapping_context
,
1232 sizeof(EMS_mapping_context
));
1235 /* Find the next free handle, returns -1 if there are no more handles */
1237 find_next_free_handle(void)
1241 if (ems_alloc_handles
>= 255)
1243 /* handle 0 is OS handle */
1244 for (i
= 1; i
< EMS_NUM_HANDLES
; i
++) {
1245 if (ems_handle
[i
] == NULL
)
1248 fatal("EMS handle count garbled, should not happen\n");
1249 /* quiet 'gcc -Wall' */
1253 /* Look for a named handle, returns 0 if not found, else handle */
1255 lookup_handle(Hname
*hp
)
1259 for (i
= 1; i
< EMS_NUM_HANDLES
; i
++) {
1260 if (ems_handle
[i
] != NULL
) {
1261 if (hp
->ul_hn
[0] == ems_handle
[i
]->hname
.ul_hn
[0] &&
1262 hp
->ul_hn
[1] == ems_handle
[i
]->hname
.ul_hn
[1])
1269 /* Malloc a new handle struct and put into array at index handle */
1271 allocate_handle(short handle
, long npages
)
1273 if (ems_handle
[handle
] != NULL
)
1274 fatal("EMS allocate_handle, handle was not free\n");
1275 ems_handle
[handle
] = get_new_handle(npages
);
1276 ems_alloc_handles
++;
1279 /* Free a handle, return its memory. Call this *after* freeing the
1283 free_handle(short handle
)
1285 if (ems_handle
[handle
] == NULL
)
1286 fatal("EMS free_handle, handle was free\n");
1287 if (ems_handle
[handle
]->mcontext
!= NULL
)
1288 free((void *)ems_handle
[handle
]->mcontext
);
1289 free((void *)ems_handle
[handle
]);
1290 ems_handle
[handle
] = NULL
;
1291 ems_alloc_handles
--;
1295 /* Allocates npages to handle. Call this routine only after you have
1296 * ensured there are enough free pages *and* the new handle is in place
1297 * in the handle array !
1300 allocate_pages_to_handle(u_short handle
, long npages
)
1302 unsigned syspagenum
;
1303 int pages_to_alloc
= npages
;
1304 int allocpagenum
= 0;
1307 if (handle
> 255 || ems_handle
[handle
] == NULL
)
1308 fatal("EMS allocate_pages_to_handle called with invalid handle\n");
1310 ems_handle
[handle
]->npages
= npages
;
1311 for (syspagenum
= 0; syspagenum
< ems_total_pages
; syspagenum
++) {
1312 if (ems_page
[syspagenum
].status
== EMS_FREE
) {
1313 ems_page
[syspagenum
].handle
= handle
;
1314 ems_page
[syspagenum
].status
= EMS_ALLOCED
;
1315 ems_handle
[handle
]->pagenum
[allocpagenum
] = syspagenum
;
1318 if (pages_to_alloc
== 0)
1322 if (pages_to_alloc
> 0)
1323 fatal("EMS allocate_pages_to_handle found not enough free pages\n");
1324 ems_alloc_pages
+= npages
;
1325 ems_free_pages
-= npages
;
1328 /* Reallocates npages to handle. Call this routine only after you have
1329 * ensured there are enough free pages *and* the new handle is in place
1330 * in the handle array !
1333 reallocate_pages_to_handle(u_short handle
, long npages
)
1335 unsigned allocpagenum
;
1336 unsigned syspagenum
;
1343 if (handle
> 255 || ems_handle
[handle
] == NULL
)
1344 fatal("EMS allocate_pages_to_handle called with invalid handle\n");
1346 delta
= npages
- ems_handle
[handle
]->npages
;
1348 /* Grow array size and allocation */
1350 emp
= ems_handle
[handle
];
1351 dynsize
= sizeof(EMS_handle
) + sizeof(short) * npages
;
1353 /* First step: Make room in the handle pagenum array */
1354 if ((emp
= (EMS_handle
*)realloc((void *)emp
, dynsize
)) == NULL
)
1355 fatal("Cannot malloc EMS handle, cannot continue\n");
1356 ems_handle
[handle
] = emp
;
1358 /* Second step: Add pages to the handle */
1359 pages_to_alloc
= delta
;
1360 allocpagenum
= ems_handle
[handle
]->npages
;
1361 ems_handle
[handle
]->npages
= npages
;
1362 for (syspagenum
= 0; syspagenum
< ems_total_pages
; syspagenum
++) {
1363 if (ems_page
[syspagenum
].status
== EMS_FREE
) {
1364 ems_page
[syspagenum
].handle
= handle
;
1365 ems_page
[syspagenum
].status
= EMS_ALLOCED
;
1366 ems_handle
[handle
]->pagenum
[allocpagenum
] = syspagenum
;
1369 if (pages_to_alloc
== 0)
1373 if (pages_to_alloc
> 0)
1374 fatal("EMS allocate_pages_to_handle found not enough free pages\n");
1377 /* Shrink array size and allocation */
1379 /* First step: Deallocate all pages from new size to old size */
1380 for (allocpagenum
= npages
;
1381 allocpagenum
< ems_handle
[handle
]->npages
;
1383 syspagenum
= ems_handle
[handle
]->pagenum
[allocpagenum
];
1386 if (syspagenum
> ems_total_pages
)
1387 fatal("EMS free_pages_of_handle found invalid page number\n");
1388 if (!(ems_page
[syspagenum
].status
& EMS_ALLOCED
))
1389 fatal("EMS free_pages_of_handle tried to free page already free\n");
1390 ems_page
[syspagenum
].handle
= 0;
1391 ems_page
[syspagenum
].status
= EMS_FREE
;
1394 /* Second step: Shrink the dynamic array of the handle */
1395 dynsize
= sizeof(EMS_handle
) + sizeof(short) * npages
;
1396 emp
= ems_handle
[handle
];
1397 if ((emp
= (EMS_handle
*)realloc((void *)emp
, dynsize
)) == NULL
)
1398 fatal("Cannot realloc EMS handle, cannot continue\n");
1399 ems_handle
[handle
] = emp
;
1400 ems_handle
[handle
]->npages
= npages
;
1402 ems_alloc_pages
+= delta
;
1403 ems_free_pages
-= delta
;
1406 /* Free all pages belonging to a handle, handle must be valid */
1408 free_pages_of_handle(short handle
)
1411 unsigned syspagenum
;
1416 if (handle
> 255 || ems_handle
[handle
] == NULL
)
1417 fatal("EMS free_pages_of_handle called with invalid handle\n");
1419 if ((npages
= ems_handle
[handle
]->npages
) == 0)
1422 for (allocpagenum
= 0; allocpagenum
< npages
; allocpagenum
++) {
1423 syspagenum
= ems_handle
[handle
]->pagenum
[allocpagenum
];
1425 if (syspagenum
> ems_total_pages
)
1426 fatal("EMS free_pages_of_handle found invalid page number\n");
1427 if (!(ems_page
[syspagenum
].status
& EMS_ALLOCED
))
1428 fatal("EMS free_pages_of_handle tried to free page already free\n");
1429 ems_page
[syspagenum
].handle
= 0;
1430 ems_page
[syspagenum
].status
= EMS_FREE
;
1432 ems_alloc_pages
-= npages
;
1433 ems_free_pages
+= npages
;
1436 /* Restore a saved mapping context, overwrites current mapping context */
1438 restore_context(EMS_mapping_context
*emc
)
1442 for (i
= 0; i
< 4; i
++) {
1443 ems_mapping_context
.handle
[i
] = emc
->handle
[i
];
1444 if (emc
->pos_mapped
[i
] != 0 &&
1445 ems_mapping_context
.pos_pagenum
[i
] != emc
->pos_pagenum
[i
]) {
1446 map_page(emc
->pos_pagenum
[i
], (u_char
) i
, emc
->handle
[i
], 0);
1448 ems_mapping_context
.pos_mapped
[i
] = 0;
1453 /* Prepare a special context save block for DOS and save it to
1457 save_context_to_dos(EMScontext
*emp
)
1464 context
.ems_saved_context
= ems_mapping_context
;
1465 context
.magic
= EMS_SAVEMAGIC
;
1466 context
.checksum
= 0;
1467 sp
= (u_short
*)&context
;
1468 end
= sizeof(EMScontext
) / sizeof(short);
1469 /* Generate checksum */
1470 for (i
= 0, sum
= 0; i
< end
; i
++) {
1474 context
.checksum
= 0x10000L
- sum
;
1475 /* Save it to VM86 memory */
1479 /* Check a context returned from VM86 app for validity, return 0, if
1480 * not valid, else return 1
1483 check_saved_context(EMScontext
*emp
)
1489 if (emp
->magic
!= EMS_SAVEMAGIC
)
1492 sp
= (u_short
*)emp
;
1493 end
= sizeof(EMScontext
) / sizeof(short);
1494 /* Generate checksum */
1495 for (i
= 0, sum
= 0; i
< end
; i
++) {
1505 /* Helper routine for the move routines below: Check if length bytes
1506 * can be moved from/to handle pages (i.e are there enough pages)
1509 check_alloc_pages(u_short handle
, u_short firstpage
, u_short offset
,
1510 u_long length __unused
)
1514 if (firstpage
> ems_handle
[handle
]->npages
)
1516 nbytes
= (ems_handle
[handle
]->npages
- firstpage
) * EMS_PAGESIZE
- offset
;
1517 return (ems_handle
[handle
]->npages
>= nbytes
);
1520 /* Copy a block of memory up to the next 16kB boundary in the source
1521 * to the destination in upward direction (i.e. with ascending addresses)
1522 * XXX Could be an inline function.
1525 copy_block_up(struct copydesc
*cdp
)
1531 /* If source or both memory types are EMS, source determines the
1532 * block lenght, else destination determines the block lenght
1534 if (cdp
->copytype
& SRC_EMS
)
1535 size
= EMS_PAGESIZE
- cdp
->EMS_OFFS(src_addr
);
1537 size
= EMS_PAGESIZE
- cdp
->EMS_OFFS(dst_addr
);
1539 if (size
> cdp
->rest_len
)
1540 size
= cdp
->rest_len
;
1542 /* If src is EMS memory, it is mapped into position 0 */
1543 if (cdp
->copytype
& SRC_EMS
)
1544 srcp
= (void *)(ems_frame_addr
+ cdp
->EMS_OFFS(src_addr
));
1546 srcp
= (void *)(cdp
->EMS_PTR(src_addr
));
1548 /* If dest is EMS memory, it is mapped into position 1,2 */
1549 if (cdp
->copytype
& DST_EMS
)
1550 dstp
= (void *)(ems_frame_addr
+ EMS_PAGESIZE
+
1551 cdp
->EMS_OFFS(dst_addr
));
1553 dstp
= (void *)(cdp
->EMS_PTR(dst_addr
));
1555 /* Move this block */
1556 memmove(dstp
, srcp
, size
);
1558 /* Update the copy descriptor: This updates the address of both
1559 * conventional and EMS memory
1561 cdp
->EMS_PTR(src_addr
) += size
;
1562 cdp
->EMS_PTR(dst_addr
) += size
;
1564 cdp
->rest_len
-= size
;
1568 /* Move EMS memory starting with handle page src_seg and offset src_offset
1569 * to conventional memory dst_addr for length bytes
1570 * dst_addr is checked, handle is valid
1573 move_ems_to_conv(short src_handle
, u_short src_seg
,
1574 u_short src_offset
, u_long dst_addr
, u_long length
)
1576 EMS_mapping_context ems_saved_context
;
1578 int pageindx
= src_seg
;
1581 if (check_alloc_pages(src_handle
, src_seg
, src_offset
, length
) == 0)
1582 return EMS_MOVE_OVERFLOW
;
1584 ehp
= ems_handle
[src_handle
];
1586 /* Prepare the move: Save the mapping context */
1587 ems_saved_context
= ems_mapping_context
;
1589 /* Setup the copy descriptor struct */
1591 cd
.copytype
= SRC_EMS
;
1592 cd
.EMS_PAGE(src_addr
) = ehp
->pagenum
[pageindx
];
1593 cd
.EMS_OFFS(src_addr
) = src_offset
;
1594 cd
.EMS_PTR(dst_addr
) = dst_addr
;
1595 cd
.rest_len
= length
;
1598 /* Map for the first block copy, source is mapped to position zero */
1599 map_page(cd
.EMS_PAGE(src_addr
), 0, src_handle
, 0);
1601 } while(cd
.rest_len
> 0);
1603 /* Restore the original mapping */
1604 restore_context(&ems_saved_context
);
1608 /* Move conventional memory starting with src_addr
1609 * to EMS memory starting with handle page src_seg and offset src_offset
1611 * dst_addr is checked, handle is valid
1614 move_conv_to_ems(u_long src_addr
, u_short dst_handle
, u_short dst_seg
,
1615 u_short dst_offset
, u_long length
)
1617 EMS_mapping_context ems_saved_context
;
1619 int pageindx
= dst_seg
;
1622 if (check_alloc_pages(dst_handle
, dst_seg
, dst_offset
, length
) == 0)
1623 return EMS_MOVE_OVERFLOW
;
1625 ehp
= ems_handle
[dst_handle
];
1627 /* Prepare the move: Save the mapping context */
1628 ems_saved_context
= ems_mapping_context
;
1630 /* Setup the copy descriptor struct */
1632 cd
.copytype
= DST_EMS
;
1633 cd
.EMS_PAGE(dst_addr
) = ehp
->pagenum
[pageindx
];
1634 cd
.EMS_OFFS(dst_addr
) = dst_offset
;
1635 cd
.EMS_PTR(src_addr
) = src_addr
;
1636 cd
.rest_len
= length
;
1639 map_page(cd
.EMS_PAGE(dst_addr
), 1, dst_handle
, 0);
1641 } while(cd
.rest_len
> 0);
1643 /* Restore the original mapping */
1644 restore_context(&ems_saved_context
);
1649 move_ems_to_ems(u_short src_handle
, u_short src_seg
, u_short src_offset
,
1650 u_short dst_handle
, u_short dst_seg
, u_short dst_offset
,
1653 EMS_mapping_context ems_saved_context
;
1654 EMS_handle
*src_hp
, *dst_hp
;
1657 if (check_alloc_pages(src_handle
, src_seg
, src_offset
, length
) == 0)
1658 return EMS_MOVE_OVERFLOW
;
1659 if (check_alloc_pages(dst_handle
, dst_seg
, dst_offset
, length
) == 0)
1660 return EMS_MOVE_OVERFLOW
;
1662 src_hp
= ems_handle
[src_handle
];
1663 dst_hp
= ems_handle
[dst_handle
];
1665 /* Prepare the move: Save the mapping context */
1666 ems_saved_context
= ems_mapping_context
;
1668 /* Setup the copy descriptor struct */
1670 cd
.copytype
= SRC_EMS
| DST_EMS
;
1671 cd
.EMS_PAGE(src_addr
) = src_hp
->pagenum
[src_seg
];
1672 cd
.EMS_OFFS(src_addr
) = src_offset
;
1673 cd
.EMS_PAGE(dst_addr
) = dst_hp
->pagenum
[dst_seg
];
1674 cd
.EMS_OFFS(dst_addr
) = dst_offset
;
1675 cd
.rest_len
= length
;
1679 map_page(cd
.EMS_PAGE(src_addr
), 0, src_handle
, 0);
1680 map_page(cd
.EMS_PAGE(dst_addr
), 1, dst_handle
, 0);
1681 /* If there are more pages, map the next destination page to
1682 * position 2. This removes a compare between source and dest
1685 if (cd
.EMS_PAGE(dst_addr
) < dst_hp
->npages
)
1686 map_page((cd
.EMS_PAGE(dst_addr
) + 1), 2, dst_handle
, 0);
1688 } while(cd
.rest_len
> 0);
1690 /* Restore the original mapping */
1691 restore_context(&ems_saved_context
);