Added support for the Win32 Console interface to the main DOSVM event
[wine.git] / loader / dos / dosvm.c
blob755ce81122105a8d7cf6c65962d61b6868599869
1 /*
2 * DOS Virtual Machine
4 * Copyright 1998 Ove Kåven
6 * This code hasn't been completely cleaned up yet.
7 */
9 #include "config.h"
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <signal.h>
17 #include <unistd.h>
18 #include <sys/time.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
22 #include "wine/winbase16.h"
23 #include "wine/exception.h"
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnt.h"
29 #include "wincon.h"
31 #include "callback.h"
32 #include "msdos.h"
33 #include "file.h"
34 #include "miscemu.h"
35 #include "dosexe.h"
36 #include "dosmod.h"
37 #include "stackframe.h"
38 #include "debugtools.h"
40 DECLARE_DEBUG_CHANNEL(int)
41 DECLARE_DEBUG_CHANNEL(module)
42 DECLARE_DEBUG_CHANNEL(relay)
44 #ifdef MZ_SUPPORTED
46 #ifdef HAVE_SYS_VM86_H
47 # include <sys/vm86.h>
48 #endif
49 #ifdef HAVE_SYS_MMAN_H
50 # include <sys/mman.h>
51 #endif
53 #define IF_CLR(ctx) EFL_reg(ctx) &= ~VIF_MASK
54 #define IF_ENABLED(ctx) (EFL_reg(ctx) & VIF_MASK)
55 #define SET_PEND(ctx) EFL_reg(ctx) |= VIP_MASK
56 #define CLR_PEND(ctx) EFL_reg(ctx) &= ~VIP_MASK
57 #define IS_PEND(ctx) (EFL_reg(ctx) & VIP_MASK)
59 #undef TRY_PICRETURN
61 static void do_exception( int signal, CONTEXT86 *context )
63 EXCEPTION_RECORD rec;
64 if ((signal == SIGTRAP) || (signal == SIGHUP))
66 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
67 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
69 else
71 rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; /* generic error */
72 rec.ExceptionFlags = EH_NONCONTINUABLE;
74 rec.ExceptionRecord = NULL;
75 rec.ExceptionAddress = (LPVOID)EIP_reg(context);
76 rec.NumberParameters = 0;
77 EXC_RtlRaiseException( &rec, context );
80 static void DOSVM_Dump( LPDOSTASK lpDosTask, int fn, int sig,
81 struct vm86plus_struct*VM86 )
83 unsigned iofs;
84 BYTE*inst;
85 int x;
87 switch (VM86_TYPE(fn)) {
88 case VM86_SIGNAL:
89 printf("Trapped signal %d\n",sig); break;
90 case VM86_UNKNOWN:
91 printf("Trapped unhandled GPF\n"); break;
92 case VM86_INTx:
93 printf("Trapped INT %02x\n",VM86_ARG(fn)); break;
94 case VM86_STI:
95 printf("Trapped STI\n"); break;
96 case VM86_PICRETURN:
97 printf("Trapped due to pending PIC request\n"); break;
98 case VM86_TRAP:
99 printf("Trapped debug request\n"); break;
100 default:
101 printf("Trapped unknown VM86 type %d arg %d\n",VM86_TYPE(fn),VM86_ARG(fn)); break;
103 #define REGS VM86->regs
104 fprintf(stderr,"AX=%04lX CX=%04lX DX=%04lX BX=%04lX\n",REGS.eax,REGS.ecx,REGS.edx,REGS.ebx);
105 fprintf(stderr,"SI=%04lX DI=%04lX SP=%04lX BP=%04lX\n",REGS.esi,REGS.edi,REGS.esp,REGS.ebp);
106 fprintf(stderr,"CS=%04X DS=%04X ES=%04X SS=%04X\n",REGS.cs,REGS.ds,REGS.es,REGS.ss);
107 fprintf(stderr,"IP=%04lX EFLAGS=%08lX\n",REGS.eip,REGS.eflags);
109 iofs=((DWORD)REGS.cs<<4)+REGS.eip;
110 #undef REGS
111 inst=(BYTE*)lpDosTask->img+iofs;
112 printf("Opcodes:");
113 for (x=0; x<8; x++) printf(" %02x",inst[x]);
114 printf("\n");
117 static int DOSVM_Int( int vect, CONTEXT86 *context, LPDOSTASK lpDosTask )
119 extern UINT16 DPMI_wrap_seg;
121 if (vect==0x31) {
122 if (CS_reg(context)==DPMI_wrap_seg) {
123 /* exit from real-mode wrapper */
124 return -1;
126 /* we could probably move some other dodgy stuff here too from dpmi.c */
128 INT_RealModeInterrupt(vect,context);
129 return 0;
132 static void DOSVM_SimulateInt( int vect, CONTEXT86 *context, LPDOSTASK lpDosTask )
134 FARPROC16 handler=INT_GetRMHandler(vect);
136 if (SELECTOROF(handler)==0xf000) {
137 /* if internal interrupt, call it directly */
138 INT_RealModeInterrupt(vect,context);
139 } else {
140 WORD*stack=(WORD*)(V86BASE(context)+(((DWORD)SS_reg(context))<<4)+LOWORD(ESP_reg(context)));
141 WORD flag=LOWORD(EFL_reg(context));
143 if (IF_ENABLED(context)) flag|=IF_MASK;
144 else flag&=~IF_MASK;
146 *(--stack)=flag;
147 *(--stack)=CS_reg(context);
148 *(--stack)=LOWORD(EIP_reg(context));
149 ESP_reg(context)-=6;
150 CS_reg(context)=SELECTOROF(handler);
151 EIP_reg(context)=OFFSETOF(handler);
152 IF_CLR(context);
156 #define SHOULD_PEND(x) \
157 (x && ((!lpDosTask->current) || (x->priority < lpDosTask->current->priority)))
159 static void DOSVM_SendQueuedEvent(CONTEXT86 *context, LPDOSTASK lpDosTask)
161 LPDOSEVENT event = lpDosTask->pending;
163 if (SHOULD_PEND(event)) {
164 /* remove from "pending" list */
165 lpDosTask->pending = event->next;
166 /* process event */
167 if (event->irq>=0) {
168 /* it's an IRQ, move it to "current" list */
169 event->next = lpDosTask->current;
170 lpDosTask->current = event;
171 TRACE_(int)("dispatching IRQ %d\n",event->irq);
172 /* note that if DOSVM_SimulateInt calls an internal interrupt directly,
173 * lpDosTask->current might be cleared (and event freed) in this very call! */
174 DOSVM_SimulateInt((event->irq<8)?(event->irq+8):(event->irq-8+0x70),context,lpDosTask);
175 } else {
176 /* callback event */
177 TRACE_(int)("dispatching callback event\n");
178 (*event->relay)(lpDosTask,context,event->data);
179 free(event);
182 if (!SHOULD_PEND(lpDosTask->pending)) {
183 TRACE_(int)("clearing Pending flag\n");
184 CLR_PEND(context);
188 static void DOSVM_SendQueuedEvents(CONTEXT86 *context, LPDOSTASK lpDosTask)
190 /* we will send all queued events as long as interrupts are enabled,
191 * but IRQ events will disable interrupts again */
192 while (IS_PEND(context) && IF_ENABLED(context))
193 DOSVM_SendQueuedEvent(context,lpDosTask);
196 void DOSVM_QueueEvent( int irq, int priority, void (*relay)(LPDOSTASK,CONTEXT86*,void*), void *data)
198 LPDOSTASK lpDosTask = MZ_Current();
199 LPDOSEVENT event, cur, prev;
201 if (lpDosTask && lpDosTask->entered) {
202 event = malloc(sizeof(DOSEVENT));
203 if (!event) {
204 ERR_(int)("out of memory allocating event entry\n");
205 return;
207 event->irq = irq; event->priority = priority;
208 event->relay = relay; event->data = data;
210 /* insert event into linked list, in order *after*
211 * all earlier events of higher or equal priority */
212 cur = lpDosTask->pending; prev = NULL;
213 while (cur && cur->priority<=priority) {
214 prev = cur;
215 cur = cur->next;
217 event->next = cur;
218 if (prev) prev->next = event;
219 else lpDosTask->pending = event;
221 /* get dosmod's attention to the new event, if necessary */
222 if (!lpDosTask->sig_sent) {
223 TRACE_(int)("new event queued, signalling dosmod\n");
224 kill(lpDosTask->task,SIGUSR2);
225 lpDosTask->sig_sent++;
226 } else {
227 TRACE_(int)("new event queued\n");
229 } else {
230 /* DOS subsystem not running */
231 /* (this probably means that we're running a win16 app
232 * which uses DPMI to thunk down to DOS services) */
233 if (irq<0) {
234 /* callback event, perform it with dummy context */
235 CONTEXT86 context;
236 memset(&context,0,sizeof(context));
237 (*relay)(lpDosTask,&context,data);
238 } else {
239 ERR_(int)("IRQ without DOS task: should not happen");
244 #define CV CP(eax,EAX); CP(ecx,ECX); CP(edx,EDX); CP(ebx,EBX); \
245 CP(esi,ESI); CP(edi,EDI); CP(esp,ESP); CP(ebp,EBP); \
246 CP(cs,CS); CP(ds,DS); CP(es,ES); \
247 CP(ss,SS); CP(fs,FS); CP(gs,GS); \
248 CP(eip,EIP); CP(eflags,EFL)
250 static int DOSVM_Process( LPDOSTASK lpDosTask, int fn, int sig,
251 struct vm86plus_struct*VM86 )
253 CONTEXT86 context;
254 int ret=0;
256 #define CP(x,y) y##_reg(&context) = VM86->regs.x
258 #undef CP
259 if (VM86_TYPE(fn)==VM86_UNKNOWN) {
260 ret=INSTR_EmulateInstruction(&context);
261 #define CP(x,y) VM86->regs.x = y##_reg(&context)
263 #undef CP
264 if (ret) return 0;
265 ret=0;
267 #ifdef TRY_PICRETURN
268 if (VM86->vm86plus.force_return_for_pic) {
269 SET_PEND(&context);
271 #else
272 /* linux doesn't preserve pending flag on return */
273 if (SHOULD_PEND(lpDosTask->pending)) {
274 SET_PEND(&context);
276 #endif
278 switch (VM86_TYPE(fn)) {
279 case VM86_SIGNAL:
280 TRACE_(int)("DOS module caught signal %d\n",sig);
281 if ((sig==SIGALRM) || (sig==SIGUSR2)) {
282 if (sig==SIGALRM) {
283 lpDosTask->sig_sent++;
284 DOSVM_QueueEvent(0,DOS_PRIORITY_REALTIME,NULL,NULL);
286 if (lpDosTask->pending) {
287 TRACE_(int)("setting Pending flag, interrupts are currently %s\n",
288 IF_ENABLED(&context) ? "enabled" : "disabled");
289 SET_PEND(&context);
290 DOSVM_SendQueuedEvents(&context,lpDosTask);
291 } else {
292 TRACE_(int)("no events are pending, clearing Pending flag\n");
293 CLR_PEND(&context);
295 lpDosTask->sig_sent--;
297 else if ((sig==SIGHUP) || (sig==SIGILL) || (sig==SIGSEGV)) {
298 do_exception( sig, &context );
299 } else {
300 DOSVM_Dump(lpDosTask,fn,sig,VM86);
301 ret=-1;
303 break;
304 case VM86_UNKNOWN: /* unhandled GPF */
305 DOSVM_Dump(lpDosTask,fn,sig,VM86);
306 do_exception( SIGSEGV, &context );
307 break;
308 case VM86_INTx:
309 if (TRACE_ON(relay))
310 DPRINTF("Call DOS int 0x%02x (EAX=%08lx) ret=%04lx:%04lx\n",VM86_ARG(fn),context.Eax,context.SegCs,context.Eip);
311 ret=DOSVM_Int(VM86_ARG(fn),&context,lpDosTask);
312 if (TRACE_ON(relay))
313 DPRINTF("Ret DOS int 0x%02x (EAX=%08lx) ret=%04lx:%04lx\n",VM86_ARG(fn),context.Eax,context.SegCs,context.Eip);
314 break;
315 case VM86_STI:
316 case VM86_PICRETURN:
317 TRACE_(int)("DOS task enabled interrupts with events pending, sending events\n");
318 DOSVM_SendQueuedEvents(&context,lpDosTask);
319 break;
320 case VM86_TRAP:
321 do_exception( SIGTRAP, &context );
322 break;
323 default:
324 DOSVM_Dump(lpDosTask,fn,sig,VM86);
325 ret=-1;
328 #define CP(x,y) VM86->regs.x = y##_reg(&context)
330 #undef CP
331 #ifdef TRY_PICRETURN
332 VM86->vm86plus.force_return_for_pic = IS_PEND(&context) ? 1 : 0;
333 CLR_PEND(&context);
334 #endif
335 return ret;
338 static void DOSVM_ProcessConsole(LPDOSTASK lpDosTask)
340 INPUT_RECORD msg;
341 DWORD res;
342 BYTE scan;
344 if (ReadConsoleInputA(GetStdHandle(STD_INPUT_HANDLE),&msg,1,&res)) {
345 switch (msg.EventType) {
346 case KEY_EVENT:
347 scan = msg.Event.KeyEvent.wVirtualScanCode;
348 if (!msg.Event.KeyEvent.bKeyDown) scan |= 0x80;
350 /* check whether extended bit is set,
351 * and if so, queue the extension prefix */
352 if (msg.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY) {
353 INT_Int09SendScan(0xE0,0);
355 INT_Int09SendScan(scan,msg.Event.KeyEvent.uChar.AsciiChar);
356 break;
357 default:
358 FIXME_(int)("unhandled console event: %d\n", msg.EventType);
363 static void DOSVM_ProcessMessage(LPDOSTASK lpDosTask,MSG *msg)
365 BYTE scan = 0;
367 TRACE_(int)("got message %04x, wparam=%08x, lparam=%08lx\n",msg->message,msg->wParam,msg->lParam);
368 if ((msg->message>=WM_MOUSEFIRST)&&
369 (msg->message<=WM_MOUSELAST)) {
370 INT_Int33Message(msg->message,msg->wParam,msg->lParam);
371 } else {
372 switch (msg->message) {
373 case WM_KEYUP:
374 scan = 0x80;
375 case WM_KEYDOWN:
376 scan |= (msg->lParam >> 16) & 0x7f;
378 /* check whether extended bit is set,
379 * and if so, queue the extension prefix */
380 if (msg->lParam & 0x1000000) {
381 /* FIXME: some keys (function keys) have
382 * extended bit set even when they shouldn't,
383 * should check for them */
384 INT_Int09SendScan(0xE0,0);
386 INT_Int09SendScan(scan,0);
387 break;
392 void DOSVM_Wait( int read_pipe, HANDLE hObject )
394 LPDOSTASK lpDosTask = MZ_Current();
395 MSG msg;
396 DWORD waitret;
397 HANDLE objs[2];
398 int objc;
399 BOOL got_msg = FALSE;
401 objs[0]=GetStdHandle(STD_INPUT_HANDLE);
402 objs[1]=hObject;
403 objc=hObject?2:1;
404 do {
405 /* check for messages (waste time before the response check below) */
406 while (Callout.PeekMessageA(&msg,0,0,0,PM_REMOVE|PM_NOYIELD)) {
407 /* got a message */
408 DOSVM_ProcessMessage(lpDosTask,&msg);
409 /* we don't need a TranslateMessage here */
410 Callout.DispatchMessageA(&msg);
411 got_msg = TRUE;
413 if (!got_msg) {
414 /* check for console input */
415 INPUT_RECORD msg;
416 DWORD num;
417 if (PeekConsoleInputA(objs[0],&msg,1,&num) && num) {
418 DOSVM_ProcessConsole(lpDosTask);
419 got_msg = TRUE;
422 if (read_pipe == -1) {
423 if (got_msg) break;
424 } else {
425 fd_set readfds;
426 struct timeval timeout={0,0};
427 /* quick check for response from dosmod
428 * (faster than doing the full blocking wait, if data already available) */
429 FD_ZERO(&readfds); FD_SET(read_pipe,&readfds);
430 if (select(read_pipe+1,&readfds,NULL,NULL,&timeout)>0)
431 break;
433 /* nothing yet, block while waiting for something to do */
434 waitret=MsgWaitForMultipleObjects(objc,objs,FALSE,INFINITE,QS_ALLINPUT);
435 if (waitret==(DWORD)-1) {
436 ERR_(module)("dosvm wait error=%ld\n",GetLastError());
438 if ((read_pipe != -1) && hObject) {
439 if (waitret==(WAIT_OBJECT_0+1)) break;
441 if (waitret==WAIT_OBJECT_0) {
442 DOSVM_ProcessConsole(lpDosTask);
444 } while (TRUE);
447 int DOSVM_Enter( CONTEXT86 *context )
449 LPDOSTASK lpDosTask = MZ_Current();
450 struct vm86plus_struct VM86;
451 int stat,len,sig;
453 if (!lpDosTask) {
454 /* MZ_CreateProcess or MZ_AllocDPMITask should have been called first */
455 ERR_(module)("dosmod has not been initialized!");
456 return -1;
459 if (context) {
460 #define CP(x,y) VM86.regs.x = y##_reg(context)
462 #undef CP
463 if (VM86.regs.eflags & IF_MASK)
464 VM86.regs.eflags |= VIF_MASK;
465 } else {
466 /* initial setup */
467 /* allocate standard DOS handles */
468 FILE_InitProcessDosHandles();
469 /* registers */
470 memset(&VM86,0,sizeof(VM86));
471 VM86.regs.cs=lpDosTask->init_cs;
472 VM86.regs.eip=lpDosTask->init_ip;
473 VM86.regs.ss=lpDosTask->init_ss;
474 VM86.regs.esp=lpDosTask->init_sp;
475 VM86.regs.ds=lpDosTask->psp_seg;
476 VM86.regs.es=lpDosTask->psp_seg;
477 VM86.regs.eflags=VIF_MASK;
478 /* hmm, what else do we need? */
481 /* main exchange loop */
482 lpDosTask->entered++;
483 do {
484 TRACE_(module)("thread is: %lx\n",GetCurrentThreadId());
485 stat = VM86_ENTER;
486 errno = 0;
487 /* transmit VM86 structure to dosmod task */
488 if (write(lpDosTask->write_pipe,&stat,sizeof(stat))!=sizeof(stat)) {
489 ERR_(module)("dosmod sync lost, errno=%d, fd=%d, pid=%d\n",errno,lpDosTask->write_pipe,getpid());
490 return -1;
492 if (write(lpDosTask->write_pipe,&VM86,sizeof(VM86))!=sizeof(VM86)) {
493 ERR_(module)("dosmod sync lost, errno=%d\n",errno);
494 return -1;
496 /* wait for response, doing other things in the meantime */
497 DOSVM_Wait(lpDosTask->read_pipe, lpDosTask->hReadPipe);
498 /* read response */
499 while (1) {
500 if ((len=read(lpDosTask->read_pipe,&stat,sizeof(stat)))==sizeof(stat)) break;
501 if (((errno==EINTR)||(errno==EAGAIN))&&(len<=0)) {
502 WARN_(module)("rereading dosmod return code due to errno=%d, result=%d\n",errno,len);
503 continue;
505 ERR_(module)("dosmod sync lost reading return code, errno=%d, result=%d\n",errno,len);
506 return -1;
508 TRACE_(module)("dosmod return code=%d\n",stat);
509 if (stat==DOSMOD_LEFTIDLE) {
510 lpDosTask->idling--;
511 continue;
513 while (1) {
514 if ((len=read(lpDosTask->read_pipe,&VM86,sizeof(VM86)))==sizeof(VM86)) break;
515 if (((errno==EINTR)||(errno==EAGAIN))&&(len<=0)) {
516 WARN_(module)("rereading dosmod VM86 structure due to errno=%d, result=%d\n",errno,len);
517 continue;
519 ERR_(module)("dosmod sync lost reading VM86 structure, errno=%d, result=%d\n",errno,len);
520 return -1;
522 if ((stat&0xff)==DOSMOD_SIGNAL) {
523 while (1) {
524 if ((len=read(lpDosTask->read_pipe,&sig,sizeof(sig)))==sizeof(sig)) break;
525 if (((errno==EINTR)||(errno==EAGAIN))&&(len<=0)) {
526 WARN_(module)("rereading dosmod signal due to errno=%d, result=%d\n",errno,len);
527 continue;
529 ERR_(module)("dosmod sync lost reading signal, errno=%d, result=%d\n",errno,len);
530 return -1;
531 } while (0);
532 } else sig=0;
533 /* got response */
534 } while (DOSVM_Process(lpDosTask,stat,sig,&VM86)>=0);
535 lpDosTask->entered--;
537 if (context) {
538 #define CP(x,y) y##_reg(context) = VM86.regs.x
540 #undef CP
542 return 0;
545 void DOSVM_PIC_ioport_out( WORD port, BYTE val)
547 LPDOSTASK lpDosTask = MZ_Current();
548 LPDOSEVENT event;
550 if (lpDosTask) {
551 if ((port==0x20) && (val==0x20)) {
552 if (lpDosTask->current) {
553 /* EOI (End Of Interrupt) */
554 TRACE_(int)("received EOI for current IRQ, clearing\n");
555 event = lpDosTask->current;
556 lpDosTask->current = event->next;
557 if (event->relay)
558 (*event->relay)(lpDosTask,NULL,event->data);
559 free(event);
561 if (lpDosTask->pending &&
562 !lpDosTask->sig_sent) {
563 /* another event is pending, which we should probably
564 * be able to process now, so tell dosmod about it */
565 TRACE_(int)("another event pending, signalling dosmod\n");
566 kill(lpDosTask->task,SIGUSR2);
567 lpDosTask->sig_sent++;
569 } else {
570 WARN_(int)("EOI without active IRQ\n");
572 } else {
573 FIXME_(int)("unrecognized PIC command %02x\n",val);
578 void DOSVM_SetTimer( unsigned ticks )
580 LPDOSTASK lpDosTask = MZ_Current();
581 int stat=DOSMOD_SET_TIMER;
582 struct timeval tim;
584 if (lpDosTask) {
585 /* the PC clocks ticks at 1193180 Hz */
586 tim.tv_sec=0;
587 tim.tv_usec=((unsigned long long)ticks*1000000)/1193180;
588 /* sanity check */
589 if (!tim.tv_usec) tim.tv_usec=1;
591 if (write(lpDosTask->write_pipe,&stat,sizeof(stat))!=sizeof(stat)) {
592 ERR_(module)("dosmod sync lost, errno=%d\n",errno);
593 return;
595 if (write(lpDosTask->write_pipe,&tim,sizeof(tim))!=sizeof(tim)) {
596 ERR_(module)("dosmod sync lost, errno=%d\n",errno);
597 return;
599 /* there's no return */
603 unsigned DOSVM_GetTimer( void )
605 LPDOSTASK lpDosTask = MZ_Current();
606 int stat=DOSMOD_GET_TIMER;
607 struct timeval tim;
609 if (lpDosTask) {
610 if (write(lpDosTask->write_pipe,&stat,sizeof(stat))!=sizeof(stat)) {
611 ERR_(module)("dosmod sync lost, errno=%d\n",errno);
612 return 0;
614 /* read response */
615 while (1) {
616 if (read(lpDosTask->read_pipe,&tim,sizeof(tim))==sizeof(tim)) break;
617 if ((errno==EINTR)||(errno==EAGAIN)) continue;
618 ERR_(module)("dosmod sync lost, errno=%d\n",errno);
619 return 0;
621 return ((unsigned long long)tim.tv_usec*1193180)/1000000;
623 return 0;
626 void DOSVM_SetSystemData( int id, void *data )
628 LPDOSTASK lpDosTask = MZ_Current();
629 DOSSYSTEM *sys, *prev;
631 if (lpDosTask) {
632 sys = lpDosTask->sys;
633 prev = NULL;
634 while (sys && (sys->id != id)) {
635 prev = sys;
636 sys = sys->next;
638 if (sys) {
639 free(sys->data);
640 sys->data = data;
641 } else {
642 sys = malloc(sizeof(DOSSYSTEM));
643 sys->id = id;
644 sys->data = data;
645 sys->next = NULL;
646 if (prev) prev->next = sys;
647 else lpDosTask->sys = sys;
649 } else free(data);
652 void* DOSVM_GetSystemData( int id )
654 LPDOSTASK lpDosTask = MZ_Current();
655 DOSSYSTEM *sys;
657 if (lpDosTask) {
658 sys = lpDosTask->sys;
659 while (sys && (sys->id != id))
660 sys = sys->next;
661 if (sys)
662 return sys->data;
664 return NULL;
667 #else /* !MZ_SUPPORTED */
669 int DOSVM_Enter( CONTEXT86 *context )
671 ERR_(module)("DOS realmode not supported on this architecture!\n");
672 return -1;
675 void DOSVM_Wait( int read_pipe, HANDLE hObject) {}
676 void DOSVM_PIC_ioport_out( WORD port, BYTE val) {}
677 void DOSVM_SetTimer( unsigned ticks ) {}
678 unsigned DOSVM_GetTimer( void ) { return 0; }
679 void DOSVM_SetSystemData( int id, void *data ) { free(data); }
680 void* DOSVM_GetSystemData( int id ) { return NULL; }
681 void DOSVM_QueueEvent( int irq, int priority, void (*relay)(LPDOSTASK,CONTEXT86*,void*), void *data)
683 if (irq<0) {
684 /* callback event, perform it with dummy context */
685 CONTEXT86 context;
686 memset(&context,0,sizeof(context));
687 (*relay)(lpDosTask,&context,data);
688 } else {
689 ERR_(int)("IRQ without DOS task: should not happen");
693 #endif