2 * Int67 (EMS) emulation
6 #include "wine/winbase16.h"
9 #include "debugtools.h"
11 DEFAULT_DEBUG_CHANNEL(int);
14 * EMS page size == 16 kilobytes.
16 #define EMS_PAGE_SIZE (16*1024)
19 * Linear address of EMS page.
21 #define EMS_PAGE_ADDRESS(base,page) (((char*)base) + EMS_PAGE_SIZE * page)
24 * Maximum number of pages that can be allocated using EMS.
26 #define EMS_MAX_PAGES 1024
29 * Maximum number of EMS handles (allocated blocks).
31 #define EMS_MAX_HANDLES 256
34 * Global EMM Import Record.
35 * Applications can get address of this record
36 * and directly access allocated memory if they use
39 * FIXME: Missing lots of fields, packing is not correct.
44 UCHAR hindex; /* handle number */
45 BYTE flags; /* bit 0: normal handle rather than system handle */
46 char name[8]; /* handle name */
47 WORD pages; /* allocated pages */
48 void *address; /* physical address*/
49 } handle[EMS_MAX_HANDLES];
51 /* Wine specific fields... */
53 int used_pages; /* Number of allocated pages. */
54 void *frame_address; /* Address of 64k EMS page frame */
55 WORD frame_selector; /* Segment of 64k EMS page frame */
58 UCHAR hindex; /* handle number */
59 WORD logical_page; /* logical page */
64 /**********************************************************************
67 * Allocates and initialized page frame and EMS global import record.
69 static void EMS_init(void)
72 * FIXME: Should dynamically allocate upper memory block for EMS frame.
79 EMS_record = HeapAlloc(GetProcessHeap(),
83 EMS_record->frame_address = DOSMEM_MapDosToLinear(base);
84 EMS_record->frame_selector = base >> 4;
87 /**********************************************************************
90 * Get handle and allocate memory.
92 static void EMS_alloc( CONTEXT86 *context )
94 int hindex = 1; /* handle zero is reserved for system */
96 while(hindex < EMS_MAX_HANDLES && EMS_record->handle[hindex].address)
99 if(hindex == EMS_MAX_HANDLES) {
100 AH_reg(context) = 0x85; /* status: no more handles available */
102 int pages = BX_reg(context);
103 void *buffer = HeapAlloc( GetProcessHeap(), 0, pages * EMS_PAGE_SIZE );
106 AH_reg(context) = 0x88; /* status: insufficient pages available */
108 EMS_record->handle[hindex].address = buffer;
109 EMS_record->handle[hindex].pages = pages;
110 EMS_record->used_pages += pages;
112 DX_reg(context) = hindex; /* handle to allocated memory*/
113 AH_reg(context) = 0; /* status: ok */
118 /**********************************************************************
121 * Get/set handle name.
123 static void EMS_access_name( CONTEXT86 *context )
126 int hindex = DX_reg(context);
127 if(hindex < 0 || hindex >= EMS_MAX_HANDLES) {
128 AH_reg(context) = 0x83; /* invalid handle */
132 switch AL_reg(context) {
133 case 0x00: /* get name */
134 ptr = MapSL(MAKESEGPTR(context->SegEs, DI_reg(context)));
135 memcpy(ptr, EMS_record->handle[hindex].name, 8);
139 case 0x01: /* set name */
140 ptr = MapSL(MAKESEGPTR(context->SegDs, SI_reg(context)));
141 memcpy(EMS_record->handle[hindex].name, ptr, 8);
146 INT_BARF(context,0x67);
151 /**********************************************************************
154 * Map logical page into physical page.
156 static void EMS_map( CONTEXT86 *context )
158 int physical_page = AL_reg(context);
159 int new_hindex = DX_reg(context);
160 int new_logical_page = BX_reg(context);
162 int old_hindex = EMS_record->mapping[physical_page].hindex;
163 int old_logical_page = EMS_record->mapping[physical_page].logical_page;
165 void *physical_address = EMS_PAGE_ADDRESS(EMS_record->frame_address,
170 void *ptr = EMS_PAGE_ADDRESS(EMS_record->handle[old_hindex].address,
172 memcpy(ptr, physical_address, EMS_PAGE_SIZE);
176 if(new_hindex && new_logical_page != 0xffff) {
177 void *ptr = EMS_PAGE_ADDRESS(EMS_record->handle[new_hindex].address,
179 memcpy(physical_address, ptr, EMS_PAGE_SIZE);
180 EMS_record->mapping[physical_page].hindex = new_hindex;
181 EMS_record->mapping[physical_page].logical_page = new_logical_page;
183 EMS_record->mapping[physical_page].hindex = 0;
184 EMS_record->mapping[physical_page].logical_page = 0;
187 AH_reg(context) = 0; /* status: ok */
190 /**********************************************************************
193 * Free memory and release handle.
195 static void EMS_free( CONTEXT86 *context )
197 int hindex = DX_reg(context);
200 if(hindex < 0 || hindex >= EMS_MAX_HANDLES) {
201 AH_reg(context) = 0x83; /* status: invalid handle */
205 if(!EMS_record->handle[hindex].address) {
206 AH_reg(context) = 0; /* status: ok */
210 EMS_record->used_pages -= EMS_record->handle[hindex].pages;
214 if(EMS_record->mapping[i].hindex == hindex)
215 EMS_record->mapping[i].hindex = 0;
218 HeapFree( GetProcessHeap(), 0, EMS_record->handle[hindex].address );
219 EMS_record->handle[hindex].address = 0;
221 AH_reg(context) = 0; /* status: ok */
224 /**********************************************************************
227 * Handler for interrupt 67h EMS routines.
229 void WINAPI DOSVM_Int67Handler( CONTEXT86 *context )
231 switch AH_reg(context) {
233 case 0x40: /* EMS - GET MANAGER STATUS */
234 AH_reg(context) = 0; /* status: ok */
237 case 0x41: /* EMS - GET PAGE FRAME SEGMENT */
239 BX_reg(context) = EMS_record->frame_selector; /* segment of page frame */
240 AH_reg(context) = 0; /* status: ok */
243 case 0x42: /* EMS - GET NUMBER OF PAGES */
245 /* unallocated 16k pages */
246 BX_reg(context) = EMS_MAX_PAGES - EMS_record->used_pages;
247 /* total number of 16k pages */
248 DX_reg(context) = EMS_MAX_PAGES;
253 case 0x43: /* EMS - GET HANDLE AND ALLOCATE MEMORY */
258 case 0x44: /* EMS - MAP MEMORY */
263 case 0x45: /* EMS - RELEASE HANDLE AND MEMORY */
268 case 0x46: /* EMS - GET EMM VERSION */
269 AL_reg(context) = 0x40; /* version 4.0 */
270 AH_reg(context) = 0; /* status: ok */
273 case 0x47: /* EMS - SAVE MAPPING CONTEXT */
274 case 0x48: /* EMS - RESTORE MAPPING CONTEXT */
275 INT_BARF(context,0x67);
278 case 0x49: /* EMS - reserved - GET I/O PORT ADDRESSES */
279 case 0x4a: /* EMS - reserved - GET TRANSLATION ARRAY */
280 INT_BARF(context,0x67);
283 case 0x4b: /* EMS - GET NUMBER OF EMM HANDLES */
284 BX_reg(context) = EMS_MAX_HANDLES; /* EMM handles */
285 AH_reg(context) = 0; /* status: ok */
288 case 0x4c: /* EMS - GET PAGES OWNED BY HANDLE */
289 case 0x4d: /* EMS - GET PAGES FOR ALL HANDLES */
290 case 0x4e: /* EMS - GET OR SET PAGE MAP */
291 case 0x4f: /* EMS 4.0 - GET/SET PARTIAL PAGE MAP */
292 case 0x50: /* EMS 4.0 - MAP/UNMAP MULTIPLE HANDLE PAGES */
293 case 0x51: /* EMS 4.0 - REALLOCATE PAGES */
294 case 0x52: /* EMS 4.0 - GET/SET HANDLE ATTRIBUTES */
295 INT_BARF(context,0x67);
298 case 0x53: /* EMS 4.0 - GET/SET HANDLE NAME */
300 EMS_access_name(context);
303 case 0x54: /* EMS 4.0 - GET HANDLE DIRECTORY */
304 case 0x55: /* EMS 4.0 - ALTER PAGE MAP AND JUMP */
305 case 0x56: /* EMS 4.0 - ALTER PAGE MAP AND CALL */
306 case 0x57: /* EMS 4.0 - MOVE/EXCHANGE MEMORY REGION */
307 case 0x58: /* EMS 4.0 - GET MAPPABLE PHYSICAL ADDRESS ARRAY */
308 case 0x59: /* EMS 4.0 - GET EXPANDED MEMORY HARDWARE INFORMATION */
309 case 0x5a: /* EMS 4.0 - ALLOCATE STANDARD/RAW PAGES */
310 case 0x5b: /* EMS 4.0 - ALTERNATE MAP REGISTER SET */
311 case 0x5c: /* EMS 4.0 - PREPARE EXPANDED MEMORY HARDWARE FOR WARM BOOT */
312 case 0x5d: /* EMS 4.0 - ENABLE/DISABLE OS FUNCTION SET FUNCTIONS */
314 INT_BARF(context,0x67);
319 /**********************************************************************
322 * Handler for interrupt 21h IOCTL routine for device "EMMXXXX0".
324 void WINAPI EMS_Ioctl_Handler( CONTEXT86 *context )
326 assert(AH_reg(context) == 0x44);
328 switch AL_reg(context) {
329 case 0x00: /* IOCTL - GET DEVICE INFORMATION */
330 RESET_CFLAG(context); /* operation was successful */
331 DX_reg(context) = 0x4080; /* bit 14 (support ioctl read) and
332 * bit 7 (is_device) */
335 case 0x02: /* EMS - GET MEMORY MANAGER INFORMATION */
337 * This is what is called "Windows Global EMM Import Specification".
338 * Undocumented of course! Supports three requests:
339 * GET API ENTRY POINT
340 * GET EMM IMPORT STRUCTURE ADDRESS
341 * GET MEMORY MANAGER VERSION
343 INT_BARF(context,0x21);
346 case 0x07: /* IOCTL - GET OUTPUT STATUS */
347 RESET_CFLAG(context); /* operation was successful */
348 AL_reg(context) = 0xff; /* device is ready */
352 INT_BARF(context,0x21);