dosvm.c 18.1 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * DOS Virtual Machine
 *
 * Copyright 1998 Ove Kven
Alexandre Julliard's avatar
Alexandre Julliard committed
5 6
 *
 * This code hasn't been completely cleaned up yet.
Alexandre Julliard's avatar
Alexandre Julliard committed
7 8
 */

9 10
#include "config.h"

Alexandre Julliard's avatar
Alexandre Julliard committed
11 12 13 14 15 16 17
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
18
#include <sys/time.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20
#include <sys/types.h>
#include <sys/stat.h>
21 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"
Alexandre Julliard's avatar
Alexandre Julliard committed
28
#include "winnt.h"
29
#include "wincon.h"
30

Alexandre Julliard's avatar
Alexandre Julliard committed
31
#include "msdos.h"
32
#include "file.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
33 34
#include "miscemu.h"
#include "dosexe.h"
35
#include "../../loader/dos/dosmod.h"
36
#include "stackframe.h"
37
#include "debugtools.h"
38

39 40 41
DECLARE_DEBUG_CHANNEL(int);
DECLARE_DEBUG_CHANNEL(module);
DECLARE_DEBUG_CHANNEL(relay);
42

Alexandre Julliard's avatar
Alexandre Julliard committed
43 44
#ifdef MZ_SUPPORTED

45 46 47 48 49 50
#ifdef HAVE_SYS_VM86_H
# include <sys/vm86.h>
#endif
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
51

52
#define IF_CLR(ctx)     ((ctx)->EFlags &= ~VIF_MASK)
53
#define IF_SET(ctx)     ((ctx)->EFlags |= VIF_MASK)
54 55 56 57
#define IF_ENABLED(ctx) ((ctx)->EFlags & VIF_MASK)
#define SET_PEND(ctx)   ((ctx)->EFlags |= VIP_MASK)
#define CLR_PEND(ctx)   ((ctx)->EFlags &= ~VIP_MASK)
#define IS_PEND(ctx)    ((ctx)->EFlags & VIP_MASK)
58 59 60

#undef TRY_PICRETURN

61 62
typedef struct _DOSEVENT {
  int irq,priority;
63
  DOSRELAY relay;
64 65 66 67 68 69
  void *data;
  struct _DOSEVENT *next;
} DOSEVENT, *LPDOSEVENT;

static struct _DOSEVENT *pending_event, *current_event;
static int sig_sent, entered;
70
static CONTEXT86 *current_context;
71 72 73 74 75 76

/* from module.c */
extern int read_pipe, write_pipe;
extern HANDLE hReadPipe;
extern pid_t dosmod_pid;

77
static void do_exception( int signal, CONTEXT86 *context )
78 79 80 81 82 83 84 85 86 87 88 89 90
{
    EXCEPTION_RECORD rec;
    if ((signal == SIGTRAP) || (signal == SIGHUP))
    {
        rec.ExceptionCode  = EXCEPTION_BREAKPOINT;
        rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
    }
    else
    {
        rec.ExceptionCode  = EXCEPTION_ILLEGAL_INSTRUCTION;  /* generic error */
        rec.ExceptionFlags = EH_NONCONTINUABLE;
    }
    rec.ExceptionRecord  = NULL;
91
    rec.ExceptionAddress = (LPVOID)context->Eip;
92
    rec.NumberParameters = 0;
93
    EXC_RtlRaiseException( &rec, context );
94 95
}

96
static void DOSVM_Dump( int fn, int sig, struct vm86plus_struct*VM86 )
Alexandre Julliard's avatar
Alexandre Julliard committed
97 98 99 100
{
 BYTE*inst;
 int x;

101
 switch (VM86_TYPE(fn)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
102
  case VM86_SIGNAL:
103
   printf("Trapped signal %d\n",sig); break;
Alexandre Julliard's avatar
Alexandre Julliard committed
104 105 106
  case VM86_UNKNOWN:
   printf("Trapped unhandled GPF\n"); break;
  case VM86_INTx:
107
   printf("Trapped INT %02x\n",VM86_ARG(fn)); break;
Alexandre Julliard's avatar
Alexandre Julliard committed
108 109 110 111 112 113
  case VM86_STI:
   printf("Trapped STI\n"); break;
  case VM86_PICRETURN:
   printf("Trapped due to pending PIC request\n"); break;
  case VM86_TRAP:
   printf("Trapped debug request\n"); break;
114 115
  default:
   printf("Trapped unknown VM86 type %d arg %d\n",VM86_TYPE(fn),VM86_ARG(fn)); break;
Alexandre Julliard's avatar
Alexandre Julliard committed
116
 }
117
#define REGS VM86->regs
118
 fprintf(stderr,"AX=%04lX CX=%04lX DX=%04lX BX=%04lX\n",REGS.eax,REGS.ecx,REGS.edx,REGS.ebx);
Alexandre Julliard's avatar
Alexandre Julliard committed
119 120
 fprintf(stderr,"SI=%04lX DI=%04lX SP=%04lX BP=%04lX\n",REGS.esi,REGS.edi,REGS.esp,REGS.ebp);
 fprintf(stderr,"CS=%04X DS=%04X ES=%04X SS=%04X\n",REGS.cs,REGS.ds,REGS.es,REGS.ss);
121
 fprintf(stderr,"IP=%04lX EFLAGS=%08lX\n",REGS.eip,REGS.eflags);
Alexandre Julliard's avatar
Alexandre Julliard committed
122

123
 inst = PTR_REAL_TO_LIN( REGS.cs, REGS.eip );
Alexandre Julliard's avatar
Alexandre Julliard committed
124 125 126 127 128 129
#undef REGS
 printf("Opcodes:");
 for (x=0; x<8; x++) printf(" %02x",inst[x]);
 printf("\n");
}

130
static int DOSVM_SimulateInt( int vect, CONTEXT86 *context, BOOL inwine )
131
{
132 133
  FARPROC16 handler=INT_GetRMHandler(vect);

134 135 136 137 138 139 140 141 142
  /* check for our real-mode hooks */
  if (vect==0x31) {
    if (context->SegCs==DOSMEM_wrap_seg) {
      /* exit from real-mode wrapper */
      return -1;
    }
    /* we could probably move some other dodgy stuff here too from dpmi.c */
  }
  /* check if the call is from our fake BIOS interrupt stubs */
143 144 145 146 147
  if ((context->SegCs==0xf000) && !inwine) {
    if (vect != (context->Eip/4)) {
      TRACE_(int)("something fishy going on here (interrupt stub is %02lx)\n", context->Eip/4);
    }
    TRACE_(int)("builtin interrupt %02x has been branched to\n", vect);
148 149 150 151 152
    INT_RealModeInterrupt(vect, context);
  }
  /* check if the call goes to an unhooked interrupt */
  else if (SELECTOROF(handler)==0xf000) {
    /* if so, call it directly */
153
    TRACE_(int)("builtin interrupt %02x has been invoked (through vector %02x)\n", OFFSETOF(handler)/4, vect);
154 155 156 157
    INT_RealModeInterrupt(OFFSETOF(handler)/4, context);
  }
  /* the interrupt is hooked, simulate interrupt in DOS space */
  else {
158
    WORD*stack= PTR_REAL_TO_LIN( context->SegSs, context->Esp );
159
    WORD flag=LOWORD(context->EFlags);
160 161 162 163 164

    if (IF_ENABLED(context)) flag|=IF_MASK;
    else flag&=~IF_MASK;

    *(--stack)=flag;
165 166 167 168 169
    *(--stack)=context->SegCs;
    *(--stack)=LOWORD(context->Eip);
    context->Esp-=6;
    context->SegCs=SELECTOROF(handler);
    context->Eip=OFFSETOF(handler);
170 171
    IF_CLR(context);
  }
172
  return 0;
173 174 175
}

#define SHOULD_PEND(x) \
176
  (x && ((!current_event) || (x->priority < current_event->priority)))
177

178
static void DOSVM_SendQueuedEvent(CONTEXT86 *context)
179
{
180
  LPDOSEVENT event = pending_event;
181 182 183

  if (SHOULD_PEND(event)) {
    /* remove from "pending" list */
184
    pending_event = event->next;
185 186 187
    /* process event */
    if (event->irq>=0) {
      /* it's an IRQ, move it to "current" list */
188 189
      event->next = current_event;
      current_event = event;
190
      TRACE_(int)("dispatching IRQ %d\n",event->irq);
191
      /* note that if DOSVM_SimulateInt calls an internal interrupt directly,
192
       * current_event might be cleared (and event freed) in this very call! */
193
      DOSVM_SimulateInt((event->irq<8)?(event->irq+8):(event->irq-8+0x70),context,TRUE);
194 195
    } else {
      /* callback event */
196
      TRACE_(int)("dispatching callback event\n");
197
      (*event->relay)(context,event->data);
198 199 200
      free(event);
    }
  }
201
  if (!SHOULD_PEND(pending_event)) {
202
    TRACE_(int)("clearing Pending flag\n");
203 204 205 206
    CLR_PEND(context);
  }
}

207
static void DOSVM_SendQueuedEvents(CONTEXT86 *context)
208 209 210 211
{
  /* we will send all queued events as long as interrupts are enabled,
   * but IRQ events will disable interrupts again */
  while (IS_PEND(context) && IF_ENABLED(context))
212
    DOSVM_SendQueuedEvent(context);
213 214
}

215
void WINAPI DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data)
216 217 218
{
  LPDOSEVENT event, cur, prev;

219
  if (entered) {
220 221
    event = malloc(sizeof(DOSEVENT));
    if (!event) {
222
      ERR_(int)("out of memory allocating event entry\n");
223 224 225 226 227 228 229
      return;
    }
    event->irq = irq; event->priority = priority;
    event->relay = relay; event->data = data;

    /* insert event into linked list, in order *after*
     * all earlier events of higher or equal priority */
230
    cur = pending_event; prev = NULL;
231 232 233 234 235 236
    while (cur && cur->priority<=priority) {
      prev = cur;
      cur = cur->next;
    }
    event->next = cur;
    if (prev) prev->next = event;
237
    else pending_event = event;
238
    
239
    /* get dosmod's attention to the new event, if necessary */
240
    if (!sig_sent) {
241
      TRACE_(int)("new event queued, signalling dosmod\n");
242 243
      kill(dosmod_pid,SIGUSR2);
      sig_sent++;
244
    } else {
245
      TRACE_(int)("new event queued\n");
246
    }
247 248 249 250 251 252 253 254
  } else {
    /* DOS subsystem not running */
    /* (this probably means that we're running a win16 app
     *  which uses DPMI to thunk down to DOS services) */
    if (irq<0) {
      /* callback event, perform it with dummy context */
      CONTEXT86 context;
      memset(&context,0,sizeof(context));
255
      (*relay)(&context,data);
256 257 258
    } else {
      ERR_(int)("IRQ without DOS task: should not happen");
    }
259
  }
260 261
}

262 263 264 265 266
#define CV do { CP(eax,Eax); CP(ecx,Ecx); CP(edx,Edx); CP(ebx,Ebx); \
           CP(esi,Esi); CP(edi,Edi); CP(esp,Esp); CP(ebp,Ebp); \
           CP(cs,SegCs); CP(ds,SegDs); CP(es,SegEs); \
           CP(ss,SegSs); CP(fs,SegFs); CP(gs,SegGs); \
           CP(eip,Eip); CP(eflags,EFlags); } while(0)
Alexandre Julliard's avatar
Alexandre Julliard committed
267

268
static int DOSVM_Process( int fn, int sig, struct vm86plus_struct*VM86 )
Alexandre Julliard's avatar
Alexandre Julliard committed
269
{
270
 CONTEXT86 context, *old_context;
Alexandre Julliard's avatar
Alexandre Julliard committed
271 272
 int ret=0;

273
#define CP(x,y) context.y = VM86->regs.x
274 275
  CV;
#undef CP
276 277
 if (VM86_TYPE(fn)==VM86_UNKNOWN) {
  ret=INSTR_EmulateInstruction(&context);
278
#define CP(x,y) VM86->regs.x = context.y
279 280 281 282 283
  CV;
#undef CP
  if (ret) return 0;
  ret=0;
 }
284 285 286 287 288 289
#ifdef TRY_PICRETURN
 if (VM86->vm86plus.force_return_for_pic) {
   SET_PEND(&context);
 }
#else
 /* linux doesn't preserve pending flag on return */
290
 if (SHOULD_PEND(pending_event)) {
291 292 293
   SET_PEND(&context);
 }
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
294

295 296 297
 old_context = current_context;
 current_context = &context;

298
 switch (VM86_TYPE(fn)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
299
  case VM86_SIGNAL:
300
   TRACE_(int)("DOS module caught signal %d\n",sig);
301 302
   if ((sig==SIGALRM) || (sig==SIGUSR2)) {
     if (sig==SIGALRM) {
303
       sig_sent++;
304 305
       DOSVM_QueueEvent(0,DOS_PRIORITY_REALTIME,NULL,NULL);
     }
306
     if (pending_event) {
307
       TRACE_(int)("setting Pending flag, interrupts are currently %s\n",
308 309
                 IF_ENABLED(&context) ? "enabled" : "disabled");
       SET_PEND(&context);
310
       DOSVM_SendQueuedEvents(&context);
311
     } else {
312
       TRACE_(int)("no events are pending, clearing Pending flag\n");
313 314
       CLR_PEND(&context);
     }
315
     sig_sent--;
316 317 318
   }
   else if ((sig==SIGHUP) || (sig==SIGILL) || (sig==SIGSEGV)) {
       do_exception( sig, &context );
319
   } else {
320
    DOSVM_Dump(fn,sig,VM86);
321 322 323
    ret=-1;
   }
   break;
Alexandre Julliard's avatar
Alexandre Julliard committed
324
  case VM86_UNKNOWN: /* unhandled GPF */
325
   DOSVM_Dump(fn,sig,VM86);
326
   do_exception( SIGSEGV, &context );
Alexandre Julliard's avatar
Alexandre Julliard committed
327 328
   break;
  case VM86_INTx:
329 330
   if (TRACE_ON(relay))
    DPRINTF("Call DOS int 0x%02x (EAX=%08lx) ret=%04lx:%04lx\n",VM86_ARG(fn),context.Eax,context.SegCs,context.Eip);
331
   ret=DOSVM_SimulateInt(VM86_ARG(fn),&context,FALSE);
332 333 334
   if (TRACE_ON(relay))
    DPRINTF("Ret  DOS int 0x%02x (EAX=%08lx) ret=%04lx:%04lx\n",VM86_ARG(fn),context.Eax,context.SegCs,context.Eip);
   break;
Alexandre Julliard's avatar
Alexandre Julliard committed
335
  case VM86_STI:
336 337 338
    IF_SET(&context);
  /* case VM86_PICRETURN: */
    TRACE_(int)("DOS task enabled interrupts %s events pending, sending events\n", IS_PEND(&context)?"with":"without");
339
    DOSVM_SendQueuedEvents(&context);
340
    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
341
  case VM86_TRAP:
342
   do_exception( SIGTRAP, &context );
Alexandre Julliard's avatar
Alexandre Julliard committed
343
   break;
Alexandre Julliard's avatar
Alexandre Julliard committed
344
  default:
345
   DOSVM_Dump(fn,sig,VM86);
346
   ret=-1;
Alexandre Julliard's avatar
Alexandre Julliard committed
347 348
 }

349 350
 current_context = old_context;

351
#define CP(x,y) VM86->regs.x = context.y
Alexandre Julliard's avatar
Alexandre Julliard committed
352 353
 CV;
#undef CP
354 355 356 357
#ifdef TRY_PICRETURN
 VM86->vm86plus.force_return_for_pic = IS_PEND(&context) ? 1 : 0;
 CLR_PEND(&context);
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
358 359 360
 return ret;
}

361
static void DOSVM_ProcessConsole(void)
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
{
  INPUT_RECORD msg;
  DWORD res;
  BYTE scan;

  if (ReadConsoleInputA(GetStdHandle(STD_INPUT_HANDLE),&msg,1,&res)) {
    switch (msg.EventType) {
    case KEY_EVENT:
      scan = msg.Event.KeyEvent.wVirtualScanCode;
      if (!msg.Event.KeyEvent.bKeyDown) scan |= 0x80;

      /* check whether extended bit is set,
       * and if so, queue the extension prefix */
      if (msg.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY) {
        INT_Int09SendScan(0xE0,0);
      }
      INT_Int09SendScan(scan,msg.Event.KeyEvent.uChar.AsciiChar);
      break;
    default:
      FIXME_(int)("unhandled console event: %d\n", msg.EventType);
    }
  }
}

386
static void DOSVM_ProcessMessage(MSG *msg)
387 388 389
{
  BYTE scan = 0;

390
  TRACE_(int)("got message %04x, wparam=%08x, lparam=%08lx\n",msg->message,msg->wParam,msg->lParam);
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
  if ((msg->message>=WM_MOUSEFIRST)&&
      (msg->message<=WM_MOUSELAST)) {
    INT_Int33Message(msg->message,msg->wParam,msg->lParam);
  } else {
    switch (msg->message) {
    case WM_KEYUP:
      scan = 0x80;
    case WM_KEYDOWN:
      scan |= (msg->lParam >> 16) & 0x7f;

      /* check whether extended bit is set,
       * and if so, queue the extension prefix */
      if (msg->lParam & 0x1000000) {
	/* FIXME: some keys (function keys) have
	 * extended bit set even when they shouldn't,
	 * should check for them */
407
	INT_Int09SendScan(0xE0,0);
408
      }
409
      INT_Int09SendScan(scan,0);
410 411 412 413 414
      break;
    }
  }
}

415
void WINAPI DOSVM_Wait( INT read_pipe, HANDLE hObject )
416 417 418
{
  MSG msg;
  DWORD waitret;
419 420
  HANDLE objs[2];
  int objc;
421 422
  BOOL got_msg = FALSE;

423
  objs[0]=GetStdHandle(STD_INPUT_HANDLE);
424 425
  objs[1]=hObject;
  objc=hObject?2:1;
426 427
  do {
    /* check for messages (waste time before the response check below) */
428
    if (PeekMessageA)
429
    {
430
        while (PeekMessageA(&msg,0,0,0,PM_REMOVE|PM_NOYIELD)) {
431 432 433
            /* got a message */
            DOSVM_ProcessMessage(&msg);
            /* we don't need a TranslateMessage here */
434
            DispatchMessageA(&msg);
435 436
            got_msg = TRUE;
        }
437
    }
438
chk_console_input:
439 440 441 442 443
    if (!got_msg) {
      /* check for console input */
      INPUT_RECORD msg;
      DWORD num;
      if (PeekConsoleInputA(objs[0],&msg,1,&num) && num) {
444
        DOSVM_ProcessConsole();
445 446 447
        got_msg = TRUE;
      }
    }
448
    if (read_pipe == -1) {
449 450 451 452 453 454 455
      /* dispatch pending events */
      if (SHOULD_PEND(pending_event)) {
        CONTEXT86 context = *current_context;
        IF_SET(&context);
        SET_PEND(&context);
        DOSVM_SendQueuedEvents(&context);
      }
456 457 458 459 460 461 462 463 464 465 466
      if (got_msg) break;
    } else {
      fd_set readfds;
      struct timeval timeout={0,0};
      /* quick check for response from dosmod
       * (faster than doing the full blocking wait, if data already available) */
      FD_ZERO(&readfds); FD_SET(read_pipe,&readfds);
      if (select(read_pipe+1,&readfds,NULL,NULL,&timeout)>0)
	break;
    }
    /* nothing yet, block while waiting for something to do */
467 468
    if (MsgWaitForMultipleObjects)
        waitret = MsgWaitForMultipleObjects(objc,objs,FALSE,INFINITE,QS_ALLINPUT);
469 470 471
    else
        waitret = WaitForMultipleObjects(objc,objs,FALSE,INFINITE);

472 473 474
    if (waitret==(DWORD)-1) {
      ERR_(module)("dosvm wait error=%ld\n",GetLastError());
    }
475 476 477
    if ((read_pipe != -1) && hObject) {
      if (waitret==(WAIT_OBJECT_0+1)) break;
    }
478 479
    if (waitret==WAIT_OBJECT_0)
      goto chk_console_input;
480 481 482
  } while (TRUE);
}

483
INT WINAPI DOSVM_Enter( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
484
{
485
 struct vm86plus_struct VM86;
486
 int stat,len,sig;
487

488
 memset(&VM86, 0, sizeof(VM86));
489
#define CP(x,y) VM86.regs.x = context->y
Alexandre Julliard's avatar
Alexandre Julliard committed
490 491
  CV;
#undef CP
492 493
  if (VM86.regs.eflags & IF_MASK)
    VM86.regs.eflags |= VIF_MASK;
Alexandre Julliard's avatar
Alexandre Julliard committed
494

495
 /* main exchange loop */
496
 entered++;
497
 do {
498
  TRACE_(module)("thread is: %lx\n",GetCurrentThreadId());
499
  stat = VM86_ENTER;
500
  errno = 0;
501
  /* transmit VM86 structure to dosmod task */
502 503
  if (write(write_pipe,&stat,sizeof(stat))!=sizeof(stat)) {
   ERR_(module)("dosmod sync lost, errno=%d, fd=%d, pid=%d\n",errno,write_pipe,getpid());
504
   return -1;
505
  }
506
  if (write(write_pipe,&VM86,sizeof(VM86))!=sizeof(VM86)) {
507
   ERR_(module)("dosmod sync lost, errno=%d\n",errno);
508
   return -1;
509
  }
510
  /* wait for response, doing other things in the meantime */
511
  DOSVM_Wait(read_pipe, hReadPipe);
512 513
  /* read response */
  while (1) {
514
    if ((len=read(read_pipe,&stat,sizeof(stat)))==sizeof(stat)) break;
515
    if (((errno==EINTR)||(errno==EAGAIN))&&(len<=0)) {
516
     WARN_(module)("rereading dosmod return code due to errno=%d, result=%d\n",errno,len);
517 518
     continue;
    }
519
    ERR_(module)("dosmod sync lost reading return code, errno=%d, result=%d\n",errno,len);
520
    return -1;
521
  }
522
  TRACE_(module)("dosmod return code=%d\n",stat);
523 524 525
  if (stat==DOSMOD_LEFTIDLE) {
    continue;
  }
526
  while (1) {
527
    if ((len=read(read_pipe,&VM86,sizeof(VM86)))==sizeof(VM86)) break;
528
    if (((errno==EINTR)||(errno==EAGAIN))&&(len<=0)) {
529
     WARN_(module)("rereading dosmod VM86 structure due to errno=%d, result=%d\n",errno,len);
530 531
     continue;
    }
532
    ERR_(module)("dosmod sync lost reading VM86 structure, errno=%d, result=%d\n",errno,len);
533
    return -1;
534
  }
535
  if ((stat&0xff)==DOSMOD_SIGNAL) {
536
    while (1) {
537
      if ((len=read(read_pipe,&sig,sizeof(sig)))==sizeof(sig)) break;
538
      if (((errno==EINTR)||(errno==EAGAIN))&&(len<=0)) {
539
	WARN_(module)("rereading dosmod signal due to errno=%d, result=%d\n",errno,len);
540 541
	continue;
      }
542
      ERR_(module)("dosmod sync lost reading signal, errno=%d, result=%d\n",errno,len);
543 544
      return -1;
    } while (0);
545
  } else sig=0;
546
  /* got response */
547 548
 } while (DOSVM_Process(stat,sig,&VM86)>=0);
 entered--;
Alexandre Julliard's avatar
Alexandre Julliard committed
549

550
#define CP(x,y) context->y = VM86.regs.x
Alexandre Julliard's avatar
Alexandre Julliard committed
551 552 553 554 555
  CV;
#undef CP
 return 0;
}

556
void WINAPI DOSVM_PIC_ioport_out( WORD port, BYTE val)
557
{
558
    LPDOSEVENT event;
559 560

    if ((port==0x20) && (val==0x20)) {
561
      if (current_event) {
562
	/* EOI (End Of Interrupt) */
563
	TRACE_(int)("received EOI for current IRQ, clearing\n");
564 565
	event = current_event;
	current_event = event->next;
566
	if (event->relay)
567
	(*event->relay)(NULL,event->data);
568 569
	free(event);

570 571
	if (pending_event &&
	    !sig_sent) {
572 573
	  /* another event is pending, which we should probably
	   * be able to process now, so tell dosmod about it */
574
	  TRACE_(int)("another event pending, signalling dosmod\n");
575 576
	  kill(dosmod_pid,SIGUSR2);
	  sig_sent++;
577 578
	}
      } else {
579
	WARN_(int)("EOI without active IRQ\n");
580 581
      }
    } else {
582
      FIXME_(int)("unrecognized PIC command %02x\n",val);
583 584 585
    }
}

586
void WINAPI DOSVM_SetTimer( UINT ticks )
587
{
588 589 590
  int stat=DOSMOD_SET_TIMER;
  struct timeval tim;

591
  if (MZ_Current()) {
592 593
    /* the PC clocks ticks at 1193180 Hz */
    tim.tv_sec=0;
594
    tim.tv_usec=MulDiv(ticks,1000000,1193180);
595 596 597
    /* sanity check */
    if (!tim.tv_usec) tim.tv_usec=1;

598
    if (write(write_pipe,&stat,sizeof(stat))!=sizeof(stat)) {
599 600 601
      ERR_(module)("dosmod sync lost, errno=%d\n",errno);
      return;
    }
602
    if (write(write_pipe,&tim,sizeof(tim))!=sizeof(tim)) {
603 604 605 606
      ERR_(module)("dosmod sync lost, errno=%d\n",errno);
      return;
    }
    /* there's no return */
607 608 609
  }
}

610
UINT WINAPI DOSVM_GetTimer( void )
611
{
612 613 614
  int stat=DOSMOD_GET_TIMER;
  struct timeval tim;

615 616
  if (MZ_Current()) {
    if (write(write_pipe,&stat,sizeof(stat))!=sizeof(stat)) {
617 618 619 620 621
      ERR_(module)("dosmod sync lost, errno=%d\n",errno);
      return 0;
    }
    /* read response */
    while (1) {
622
      if (read(read_pipe,&tim,sizeof(tim))==sizeof(tim)) break;
623 624 625 626
      if ((errno==EINTR)||(errno==EAGAIN)) continue;
      ERR_(module)("dosmod sync lost, errno=%d\n",errno);
      return 0;
    }
627
    return MulDiv(tim.tv_usec,1193180,1000000);
628
  }
629
  return 0;
630 631
}

Alexandre Julliard's avatar
Alexandre Julliard committed
632
#else /* !MZ_SUPPORTED */
Alexandre Julliard's avatar
Alexandre Julliard committed
633

634
INT WINAPI DOSVM_Enter( CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
635
{
636
 ERR_(module)("DOS realmode not supported on this architecture!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
637 638 639
 return -1;
}

640
void WINAPI DOSVM_Wait( INT read_pipe, HANDLE hObject) {}
641
void WINAPI DOSVM_PIC_ioport_out( WORD port, BYTE val) {}
642 643 644
void WINAPI DOSVM_SetTimer( UINT ticks ) {}
UINT WINAPI DOSVM_GetTimer( void ) { return 0; }
void WINAPI DOSVM_QueueEvent( INT irq, INT priority, DOSRELAY relay, LPVOID data)
645 646 647 648 649
{
  if (irq<0) {
    /* callback event, perform it with dummy context */
    CONTEXT86 context;
    memset(&context,0,sizeof(context));
650
    (*relay)(&context,data);
651 652 653 654
  } else {
    ERR_(int)("IRQ without DOS task: should not happen");
  }
}
655

Alexandre Julliard's avatar
Alexandre Julliard committed
656
#endif