Fixed ReadFile() semantics when reading asynchronously on sockets.
[wine/testsucceed.git] / dlls / winedos / int67.c
blob0f80d61fc11c4542a72fa1d68ce85b15569ffe7a
1 /*
2 * Int67 (EMS) emulation
4 * Copyright 2002 Jukka Heinonen
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <assert.h>
22 #include "wine/winbase16.h"
23 #include "dosexe.h"
24 #include "miscemu.h"
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(int);
30 * EMS page size == 16 kilobytes.
32 #define EMS_PAGE_SIZE (16*1024)
35 * Linear address of EMS page.
37 #define EMS_PAGE_ADDRESS(base,page) (((char*)base) + EMS_PAGE_SIZE * page)
39 /*
40 * Maximum number of pages that can be allocated using EMS.
42 #define EMS_MAX_PAGES 1024
44 /*
45 * Maximum number of EMS handles (allocated blocks).
47 #define EMS_MAX_HANDLES 256
50 * Global EMM Import Record.
51 * Applications can get address of this record
52 * and directly access allocated memory if they use
53 * IOCTL interface.
55 * FIXME: Missing lots of fields, packing is not correct.
58 struct {
59 struct {
60 UCHAR hindex; /* handle number */
61 BYTE flags; /* bit 0: normal handle rather than system handle */
62 char name[8]; /* handle name */
63 WORD pages; /* allocated pages */
64 void *address; /* physical address*/
65 } handle[EMS_MAX_HANDLES];
67 /* Wine specific fields... */
69 int used_pages; /* Number of allocated pages. */
70 void *frame_address; /* Address of 64k EMS page frame */
71 WORD frame_selector; /* Segment of 64k EMS page frame */
73 struct {
74 UCHAR hindex; /* handle number */
75 WORD logical_page; /* logical page */
76 } mapping[4];
78 } *EMS_record = 0;
80 /**********************************************************************
81 * EMS_init
83 * Allocates and initialized page frame and EMS global import record.
85 static void EMS_init(void)
88 * FIXME: Should dynamically allocate upper memory block for EMS frame.
90 ULONG base = 0xd0000;
92 if(EMS_record)
93 return;
95 EMS_record = HeapAlloc(GetProcessHeap(),
96 HEAP_ZERO_MEMORY,
97 sizeof(*EMS_record));
99 EMS_record->frame_address = DOSMEM_MapDosToLinear(base);
100 EMS_record->frame_selector = base >> 4;
103 /**********************************************************************
104 * EMS_alloc
106 * Get handle and allocate memory.
108 static void EMS_alloc( CONTEXT86 *context )
110 int hindex = 1; /* handle zero is reserved for system */
112 while(hindex < EMS_MAX_HANDLES && EMS_record->handle[hindex].address)
113 hindex++;
115 if(hindex == EMS_MAX_HANDLES) {
116 AH_reg(context) = 0x85; /* status: no more handles available */
117 } else {
118 int pages = BX_reg(context);
119 void *buffer = HeapAlloc( GetProcessHeap(), 0, pages * EMS_PAGE_SIZE );
121 if(!buffer) {
122 AH_reg(context) = 0x88; /* status: insufficient pages available */
123 } else {
124 EMS_record->handle[hindex].address = buffer;
125 EMS_record->handle[hindex].pages = pages;
126 EMS_record->used_pages += pages;
128 DX_reg(context) = hindex; /* handle to allocated memory*/
129 AH_reg(context) = 0; /* status: ok */
134 /**********************************************************************
135 * EMS_access_name
137 * Get/set handle name.
139 static void EMS_access_name( CONTEXT86 *context )
141 char *ptr;
142 int hindex = DX_reg(context);
143 if(hindex < 0 || hindex >= EMS_MAX_HANDLES) {
144 AH_reg(context) = 0x83; /* invalid handle */
145 return;
148 switch AL_reg(context) {
149 case 0x00: /* get name */
150 ptr = MapSL(MAKESEGPTR(context->SegEs, DI_reg(context)));
151 memcpy(ptr, EMS_record->handle[hindex].name, 8);
152 AH_reg(context) = 0;
153 break;
155 case 0x01: /* set name */
156 ptr = MapSL(MAKESEGPTR(context->SegDs, SI_reg(context)));
157 memcpy(EMS_record->handle[hindex].name, ptr, 8);
158 AH_reg(context) = 0;
159 break;
161 default:
162 INT_BARF(context,0x67);
163 break;
167 /**********************************************************************
168 * EMS_map
170 * Map logical page into physical page.
172 static void EMS_map( CONTEXT86 *context )
174 int physical_page = AL_reg(context);
175 int new_hindex = DX_reg(context);
176 int new_logical_page = BX_reg(context);
178 int old_hindex = EMS_record->mapping[physical_page].hindex;
179 int old_logical_page = EMS_record->mapping[physical_page].logical_page;
181 void *physical_address = EMS_PAGE_ADDRESS(EMS_record->frame_address,
182 physical_page);
184 /* unmap old page */
185 if(old_hindex) {
186 void *ptr = EMS_PAGE_ADDRESS(EMS_record->handle[old_hindex].address,
187 old_logical_page);
188 memcpy(ptr, physical_address, EMS_PAGE_SIZE);
191 /* map new page */
192 if(new_hindex && new_logical_page != 0xffff) {
193 void *ptr = EMS_PAGE_ADDRESS(EMS_record->handle[new_hindex].address,
194 new_logical_page);
195 memcpy(physical_address, ptr, EMS_PAGE_SIZE);
196 EMS_record->mapping[physical_page].hindex = new_hindex;
197 EMS_record->mapping[physical_page].logical_page = new_logical_page;
198 } else {
199 EMS_record->mapping[physical_page].hindex = 0;
200 EMS_record->mapping[physical_page].logical_page = 0;
203 AH_reg(context) = 0; /* status: ok */
206 /**********************************************************************
207 * EMS_free
209 * Free memory and release handle.
211 static void EMS_free( CONTEXT86 *context )
213 int hindex = DX_reg(context);
214 int i;
216 if(hindex < 0 || hindex >= EMS_MAX_HANDLES) {
217 AH_reg(context) = 0x83; /* status: invalid handle */
218 return;
221 if(!EMS_record->handle[hindex].address) {
222 AH_reg(context) = 0; /* status: ok */
223 return;
226 EMS_record->used_pages -= EMS_record->handle[hindex].pages;
228 /* unmap pages */
229 for(i=0; i<4; i++)
230 if(EMS_record->mapping[i].hindex == hindex)
231 EMS_record->mapping[i].hindex = 0;
233 /* free block */
234 HeapFree( GetProcessHeap(), 0, EMS_record->handle[hindex].address );
235 EMS_record->handle[hindex].address = 0;
237 AH_reg(context) = 0; /* status: ok */
240 /**********************************************************************
241 * DOSVM_Int67Handler
243 * Handler for interrupt 67h EMS routines.
245 void WINAPI DOSVM_Int67Handler( CONTEXT86 *context )
247 switch AH_reg(context) {
249 case 0x40: /* EMS - GET MANAGER STATUS */
250 AH_reg(context) = 0; /* status: ok */
251 break;
253 case 0x41: /* EMS - GET PAGE FRAME SEGMENT */
254 EMS_init();
255 BX_reg(context) = EMS_record->frame_selector; /* segment of page frame */
256 AH_reg(context) = 0; /* status: ok */
257 break;
259 case 0x42: /* EMS - GET NUMBER OF PAGES */
260 EMS_init();
261 /* unallocated 16k pages */
262 BX_reg(context) = EMS_MAX_PAGES - EMS_record->used_pages;
263 /* total number of 16k pages */
264 DX_reg(context) = EMS_MAX_PAGES;
265 /* status: ok */
266 AH_reg(context) = 0;
267 break;
269 case 0x43: /* EMS - GET HANDLE AND ALLOCATE MEMORY */
270 EMS_init();
271 EMS_alloc(context);
272 break;
274 case 0x44: /* EMS - MAP MEMORY */
275 EMS_init();
276 EMS_map(context);
277 break;
279 case 0x45: /* EMS - RELEASE HANDLE AND MEMORY */
280 EMS_init();
281 EMS_free(context);
282 break;
284 case 0x46: /* EMS - GET EMM VERSION */
285 AL_reg(context) = 0x40; /* version 4.0 */
286 AH_reg(context) = 0; /* status: ok */
287 break;
289 case 0x47: /* EMS - SAVE MAPPING CONTEXT */
290 case 0x48: /* EMS - RESTORE MAPPING CONTEXT */
291 INT_BARF(context,0x67);
292 break;
294 case 0x49: /* EMS - reserved - GET I/O PORT ADDRESSES */
295 case 0x4a: /* EMS - reserved - GET TRANSLATION ARRAY */
296 INT_BARF(context,0x67);
297 break;
299 case 0x4b: /* EMS - GET NUMBER OF EMM HANDLES */
300 BX_reg(context) = EMS_MAX_HANDLES; /* EMM handles */
301 AH_reg(context) = 0; /* status: ok */
302 break;
304 case 0x4c: /* EMS - GET PAGES OWNED BY HANDLE */
305 case 0x4d: /* EMS - GET PAGES FOR ALL HANDLES */
306 case 0x4e: /* EMS - GET OR SET PAGE MAP */
307 case 0x4f: /* EMS 4.0 - GET/SET PARTIAL PAGE MAP */
308 case 0x50: /* EMS 4.0 - MAP/UNMAP MULTIPLE HANDLE PAGES */
309 case 0x51: /* EMS 4.0 - REALLOCATE PAGES */
310 case 0x52: /* EMS 4.0 - GET/SET HANDLE ATTRIBUTES */
311 INT_BARF(context,0x67);
312 break;
314 case 0x53: /* EMS 4.0 - GET/SET HANDLE NAME */
315 EMS_init();
316 EMS_access_name(context);
317 break;
319 case 0x54: /* EMS 4.0 - GET HANDLE DIRECTORY */
320 case 0x55: /* EMS 4.0 - ALTER PAGE MAP AND JUMP */
321 case 0x56: /* EMS 4.0 - ALTER PAGE MAP AND CALL */
322 case 0x57: /* EMS 4.0 - MOVE/EXCHANGE MEMORY REGION */
323 case 0x58: /* EMS 4.0 - GET MAPPABLE PHYSICAL ADDRESS ARRAY */
324 case 0x59: /* EMS 4.0 - GET EXPANDED MEMORY HARDWARE INFORMATION */
325 case 0x5a: /* EMS 4.0 - ALLOCATE STANDARD/RAW PAGES */
326 case 0x5b: /* EMS 4.0 - ALTERNATE MAP REGISTER SET */
327 case 0x5c: /* EMS 4.0 - PREPARE EXPANDED MEMORY HARDWARE FOR WARM BOOT */
328 case 0x5d: /* EMS 4.0 - ENABLE/DISABLE OS FUNCTION SET FUNCTIONS */
329 default:
330 INT_BARF(context,0x67);
335 /**********************************************************************
336 * EMS_Ioctl_Handler
338 * Handler for interrupt 21h IOCTL routine for device "EMMXXXX0".
340 void WINAPI EMS_Ioctl_Handler( CONTEXT86 *context )
342 assert(AH_reg(context) == 0x44);
344 switch AL_reg(context) {
345 case 0x00: /* IOCTL - GET DEVICE INFORMATION */
346 RESET_CFLAG(context); /* operation was successful */
347 DX_reg(context) = 0x4080; /* bit 14 (support ioctl read) and
348 * bit 7 (is_device) */
349 break;
351 case 0x02: /* EMS - GET MEMORY MANAGER INFORMATION */
353 * This is what is called "Windows Global EMM Import Specification".
354 * Undocumented of course! Supports three requests:
355 * GET API ENTRY POINT
356 * GET EMM IMPORT STRUCTURE ADDRESS
357 * GET MEMORY MANAGER VERSION
359 INT_BARF(context,0x21);
360 break;
362 case 0x07: /* IOCTL - GET OUTPUT STATUS */
363 RESET_CFLAG(context); /* operation was successful */
364 AL_reg(context) = 0xff; /* device is ready */
365 break;
367 default:
368 INT_BARF(context,0x21);
369 break;