Watt-32 tcp/ip  2.2 dev-rel.10
wdpmi.c
Go to the documentation of this file.
1 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include "wattcp.h"
24 #include "strings.h"
25 #include "language.h"
26 #include "pcsed.h"
27 #include "printk.h"
28 #include "sock_ini.h"
29 #include "cpumodel.h"
30 #include "misc.h"
31 #include "wdpmi.h"
32 
33 #if defined(__MSDOS__) /* rest of file */
34 
35 /* Don't put this in config.h, but define to 1 here when it works.
36  */
37 #undef USE_EXCEPT_HANDLER
38 
39 #if defined(WATCOM386)
40  /*
41  * Values for '_Extender'
42  */
43  #define DOSX_ERGO 0
44  #define DOSX_RATIONAL 1 /* DOS4Gxx, WDOSX, Pmode/W, CauseWay, EDOS */
45  #define DOSX_PHAR_V2 2
46  #define DOSX_PHAR_V3 3
47  #define DOSX_PHAR_V4 4
48  #define DOSX_PHAR_V5 5
49  #define DOSX_PHAR_V6 6
50  #define DOSX_PHAR_V7 7
51  #define DOSX_PHAR_V8 8
52  #define DOSX_INTEL 9 /* Intel C-Builder */
53  #define DOSX_WIN386 10 /* Windows 3.11+ */
54 
55  /*
56  * Values for '_ExtenderSubtype'
57  */
58  #define XS_NONE 0
59  #define XS_RATIONAL_ZEROBASE 0
60  #define XS_RATIONAL_NONZEROBASE 1 /* Only in DOS4G Pro */
61 
62  extern void cdecl cstart_ (void);
63  extern char _Extender;
64  extern char _ExtenderSubtype;
65 #endif
66 
67 #if defined(DMC386)
68  #define int386 int86_real
69  #define int386x int86x_real
70  #define AX_REG(r) r.x.ax
71  #define BX_REG(r) r.x.bx
72  #define CX_REG(r) r.x.cx
73  #define DX_REG(r) r.x.dx
74  #define EAX_REG(r) r.e.eax
75  #define EBX_REG(r) r.e.ebx
76  #define ECX_REG(r) r.e.ecx
77  #define EDX_REG(r) r.e.edx
78  #define ESI_REG(r) r.e.esi
79  #define EDI_REG(r) r.e.edi
80  #define CARRY(r) (r.x.cflag & 1)
81 
82 #else
83  #define AX_REG(r) r.w.ax
84  #define BX_REG(r) r.w.bx
85  #define CX_REG(r) r.w.cx
86  #define DX_REG(r) r.w.dx
87  #define EAX_REG(r) r.x.eax
88  #define EBX_REG(r) r.x.ebx
89  #define ECX_REG(r) r.x.ecx
90  #define EDX_REG(r) r.x.edx
91  #define ESI_REG(r) r.x.esi
92  #define EDI_REG(r) r.x.edi
93  #define CARRY(r) (r.w.cflag & 1)
94 #endif
95 
96 #if (DOSX & (DOS4GW|POWERPAK))
97 
98 #if defined(__CCDL__)
99 #define int386 _int386
100 #endif
101 
102 WORD __dpmi_errno = 0; /* last DPMI error */
103 
104 #if (!(DOSX & POWERPAK))
105 
106 WORD causeway_ver = 0; /* major=MSB, minor=LSB */
107 BOOL dos32a_nullptr_chk = 0; /* NULL-ptr traps active */
108 
109 #define DOS32A_SIGN (('I'<<24) + ('D'<<16) + ('3'<<8) + ('2'<<0))
110 #define PMODEW_SIGN (('P'<<24) + ('M'<<16) + ('D'<<8) + ('W'<<0))
111 #define WDOSX_SIGN (('W'<<24) + ('D'<<16) + ('S'<<8) + ('X'<<0))
112 
113 #if (DOSX & DOS4GW) && defined(WATCOM386) && defined(USE_EXCEPT_HANDLER)
114  static struct FAULT_STRUC exc_struct;
115  static exceptionHook user_exc_hook = NULL;
116 
117  static void far __loadds exception_main (void);
118 #endif
119 
120 /*
121  * WDOSX and Pmode/W uses same detect function with
122  * unique signatures.
123  */
124 static BOOL is_wdosx_or_pmodew (DWORD sign)
125 {
126  union REGS reg;
127 
128 #ifdef __DJGPP__
129  reg.x.eax = 0xEEFF;
130  int86 (0x31, &reg, &reg);
131 #else
132  EAX_REG(reg) = 0xEEFF;
133  int386 (0x31, &reg, &reg);
134 #endif
135  return (EAX_REG(reg) == sign);
136 }
137 
138 BOOL dpmi_is_wdosx (void)
139 {
140  return is_wdosx_or_pmodew (WDOSX_SIGN);
141 }
142 
143 BOOL dpmi_is_pmodew (void)
144 {
145  return is_wdosx_or_pmodew (PMODEW_SIGN);
146 }
147 
148 BOOL dpmi_is_dos32a (void)
149 {
150  union REGS reg;
151 
152 #ifdef __DJGPP__
153  reg.x.eax = 0xFF89; /* Get configuation info */
154  int86 (0x21, &reg);
155 #else
156  EAX_REG(reg) = 0xFF89;
157  int386 (0x21, &reg, &reg);
158 #endif
159 
160  if (EAX_REG(reg) == DOS32A_SIGN)
161  {
162  dos32a_nullptr_chk = (EDX_REG(reg) & 0x80);
163  return (TRUE);
164  }
165  return (FALSE);
166 }
167 
168 BOOL dpmi_is_dos4gw (void)
169 {
170  union REGS reg;
171 
172 #ifdef __DJGPP__ /* I doubt DOS4GW and djgpp is possible */
173  reg.x.eax = 0xFF00;
174  reg.x.edx = 0x78;
175  int86 (0x21, &reg);
176 #else
177  EAX_REG(reg) = 0xFF00;
178  EDX_REG(reg) = 0x78;
179  int386 (0x21, &reg, &reg);
180 #endif
181  return (EAX_REG(reg) == 0xFFFF3447);
182 }
183 
184 BOOL dpmi_is_causeway (void)
185 {
186 #if defined(__DJGPP__)
187  union REGS r;
188  struct SREGS s;
189  DWORD rp;
190  char sign[10];
191 
192  s.ds = s.es = _my_ds();
193  r.x.eax = 0x3531;
194  int86x (0x21, &r, &r, &s);
195  if (s.es == 0 || !SelReadable(s.es) ||
196  __dpmi_get_segment_limit(s.es) < r.x.ebx)
197  return (FALSE);
198 
199  movedata (s.es, r.x.ebx, _my_ds(), (unsigned)&sign, sizeof(sign));
200  if (!memcmp(sign,"CAUSEWAY",8))
201  {
202  causeway_ver = (sign[8] << 8) + sign[9];
203  return (TRUE);
204  }
205 
206 #elif defined(__CCDL__)
207  /* !! to-do */
208 
209 #elif defined(__WATCOMC__)
210  union REGS r;
211  struct SREGS s;
212  BYTE _far *rp;
213 
214  EAX_REG(r) = 0x3531;
215  segread (&s);
216  int386x (0x21, &r, &r, &s);
217 
218  rp = MK_FP (s.es, EBX_REG(r)-10);
219 
220  if (s.es && SelReadable(s.es) &&
221  EAX_REG(r) < GET_LIMIT(s.es) &&
222  !_fstrncmp(rp,"CAUSEWAY",8))
223  {
224  rp += 8;
225  causeway_ver = (rp[0] << 8) + rp[1];
226  return (TRUE);
227  }
228 #endif
229  return (FALSE);
230 }
231 
232 BOOL dpmi_is_hxdos (void)
233 {
234  union REGS reg;
235  char buf[128] = { '\0' };
236 
237 #ifdef __DJGPP__
238  reg.x.eax = 0x401;
239  reg.x.edi = (DWORD) &buf;
240  int86 (0x31, &reg, &reg);
241 #else
242  EAX_REG(reg) = 0x401;
243  EDI_REG(reg) = (DWORD) &buf;
244  int386 (0x31, &reg, &reg);
245 #endif
246  return !strncmp(buf+2,"HDPMI",5);
247 }
248 
249 /*
250  * Return true name of "DOS4GW-type" extenders.
251  */
252 const char *dos4gw_extender_name (void)
253 {
254  if (dpmi_is_causeway())
255  return ("CAUSEWAY");
256  if (dpmi_is_wdosx())
257  return ("WDOSX");
258  if (dpmi_is_pmodew())
259  return ("PMODEW");
260  if (dpmi_is_hxdos())
261  return ("HXDOS");
262  if (dpmi_is_dos32a())
263  return ("DOS32A");
264  if (dpmi_is_dos4gw())
265  return ("DOS4GW");
266  return ("DOS4GW"); /* assume the rest are DOS4GW compatible */
267 }
268 
269 /*
270  * Exception handler for Causeway stubbed programs.
271  * Setup to call 'exc_func' when exception occurs.
272  */
273 int dpmi_except_handler (exceptionHook exc_func)
274 {
275 #if defined(WATCOM386) && defined(USE_EXCEPT_HANDLER)
276  union REGS r;
277  struct SREGS s;
278 
279  if (!dpmi_is_causeway())
280  {
281  __dpmi_errno = 0x8001;
282  return (0);
283  }
284 
285  __dpmi_errno = 0;
286  segread (&s);
287  s.ds = FP_SEG (exception_main); /* vector address */
288  r.x.esi = FP_OFF (exception_main);
289  s.es = FP_SEG (&exc_struct); /* info dump address */
290  r.x.edi = FP_OFF (&exc_struct);
291  r.h.cl = 1; /* 32-bit routine */
292  r.w.ax = 0xFF31; /* USER_ERR_TERM */
293  int386x (0x31, &r, &r, &s);
294  if (CARRY(r))
295  {
296  __dpmi_errno = AX_REG(r);
297  return (0);
298  }
299  r.w.ax = 0xFF30; /* SetDump */
300  r.h.cl = 0;
301  int386 (0x31, &r, &r);
302 
303  user_exc_hook = exc_func;
304  memset (&exc_struct, 0, sizeof(exc_struct));
305  dpmi_lock_region ((void*)&exc_struct, sizeof(exc_struct));
306  dpmi_lock_region ((void*)exception_main, 100);
307  return (1);
308 #else
309  ARGSUSED (exc_func);
310  __dpmi_errno = 0x8001;
311  return (0);
312 #endif
313 }
314 #endif /* !(DOSX & POWERPAK) */
315 
316 
317 void *dpmi_get_real_vector (int intr)
318 {
319  union REGS r;
320 
321  __dpmi_errno = 0;
322  EAX_REG(r) = 0x200;
323  EBX_REG(r) = (DWORD) intr;
324  int386 (0x31, &r, &r);
325  return SEG_OFS_TO_LIN (CX_REG(r), DX_REG(r));
326 }
327 
328 int dpmi_get_base_address (WORD sel, DWORD *base)
329 {
330  union REGS r;
331 
332  __dpmi_errno = 0;
333  EAX_REG(r) = 0x06;
334  EBX_REG(r) = sel;
335  int386 (0x31, &r, &r);
336  if (CARRY(r))
337  {
338  __dpmi_errno = AX_REG(r);
339  return (0);
340  }
341  *base = (CX_REG(r) << 16) + DX_REG(r);
342  return (1);
343 }
344 
345 WORD dpmi_real_malloc (WORD size, WORD *selector)
346 {
347  union REGS r;
348 
349  __dpmi_errno = 0;
350  EAX_REG(r) = 0x0100; /* DPMI allocate DOS memory */
351  EBX_REG(r) = (size + 15) / 16; /* Number of paragraphs requested */
352  int386 (0x31, &r, &r);
353  if (CARRY(r))
354  {
355  __dpmi_errno = AX_REG(r);
356  return (0);
357  }
358  *selector = DX_REG(r); /* Return selector */
359  return AX_REG(r); /* Return segment address */
360 }
361 
362 int dpmi_real_free (WORD selector)
363 {
364  union REGS r;
365 
366  __dpmi_errno = 0;
367  EAX_REG(r) = 0x101; /* DPMI free DOS memory */
368  EBX_REG(r) = selector; /* Selector to free */
369  int386 (0x31, &r, &r);
370  if (CARRY(r))
371  {
372  __dpmi_errno = AX_REG(r);
373  return (0);
374  }
375  return (1);
376 }
377 
378 int dpmi_lock_region (void *address, unsigned length)
379 {
380  union REGS r;
381  DWORD base, linear;
382 
383  if (!dpmi_get_base_address(MY_CS(),&base))
384  return (0);
385 
386  linear = base + (DWORD)address;
387  __dpmi_errno = 0;
388 
389  EAX_REG(r) = 0x600; /* DPMI Lock Linear Region */
390  EBX_REG(r) = (linear >> 16); /* Linear address in BX:CX */
391  ECX_REG(r) = (linear & 0xFFFF);
392  ESI_REG(r) = (length >> 16); /* Length in SI:DI */
393  EDI_REG(r) = (length & 0xFFFF);
394  int386 (0x31, &r, &r);
395  if (CARRY(r))
396  {
397  __dpmi_errno = AX_REG(r);
398  return (0);
399  }
400  return (1);
401 }
402 
403 int dpmi_unlock_region (void *address, unsigned length)
404 {
405  union REGS r;
406  DWORD base, linear;
407 
408  if (!dpmi_get_base_address(MY_CS(),&base))
409  return (0);
410 
411  linear = base + (DWORD)address;
412  __dpmi_errno = 0;
413 
414  EAX_REG(r) = 0x601; /* DPMI Unlock Linear Region */
415  EBX_REG(r) = (linear >> 16); /* Linear address in BX:CX */
416  ECX_REG(r) = (linear & 0xFFFF);
417  ESI_REG(r) = (length >> 16); /* Length in SI:DI */
418  EDI_REG(r) = (length & 0xFFFF);
419  int386 (0x31, &r, &r);
420  if (CARRY(r))
421  {
422  __dpmi_errno = AX_REG(r);
423  return (0);
424  }
425  return (1);
426 }
427 
428 #if !defined(__CCDL__)
429 int dpmi_real_interrupt (int intr, IREGS *reg)
430 {
431  union REGS r;
432  struct SREGS s;
433 
434  __dpmi_errno = 0;
435  memset (&r, 0, sizeof(r));
436  segread (&s);
437  EAX_REG(r) = 0x300;
438  EBX_REG(r) = intr;
439  ECX_REG(r) = 0;
440  s.es = FP_SEG (reg);
441  EDI_REG(r) = FP_OFF (reg);
442  reg->r_flags = 0;
443  reg->r_ss = reg->r_sp = 0; /* DPMI host provides stack */
444 
445  int386x (0x31, &r, &r, &s);
446  if (CARRY(r))
447  {
448  reg->r_flags |= 1;
449  __dpmi_errno = AX_REG(r);
450  return (0);
451  }
452  return (1);
453 }
454 #endif
455 
456 int dpmi_real_call_retf (IREGS *reg)
457 {
458  union REGS r;
459  struct SREGS s;
460 
461  __dpmi_errno = 0;
462  memset (&r, 0, sizeof(r));
463  segread (&s);
464  EAX_REG(r) = 0x301;
465  EBX_REG(r) = 0;
466  ECX_REG(r) = 0;
467  s.es = FP_SEG (reg);
468  EDI_REG(r) = FP_OFF (reg);
469  reg->r_flags = 0;
470  reg->r_ss = reg->r_sp = 0; /* DPMI host provides stack */
471 
472  int386x (0x31, &r, &r, &s);
473  if (CARRY(r))
474  {
475  reg->r_flags |= 1;
476  __dpmi_errno = AX_REG(r);
477  return (0);
478  }
479  return (1);
480 }
481 
482 /*
483  * PowerPak already have int386().
484  */
485 #if (defined(DMC386) || defined(MSC386) || defined(BORLAND386)) && \
486  !(DOSX & POWERPAK)
487 static int real_interrupt (int intr, IREGS *reg)
488 {
489  __asm {
490  push ebx
491  push edi
492  mov edi, reg /* es:edi -> reg */
493  mov edx, esp /* save esp */
494  mov ebx, intr
495  mov eax, 300h /* simulate real-int */
496  int 31h
497  mov esp, edx
498  xor eax, eax /* assume ok */
499  pop edi
500  pop ebx
501  jc fail
502  pop ebp
503  ret
504  }
505 fail:
506  return (-1);
507 }
508 
509 int int386 (int intno, union REGS *ireg, union REGS *oreg)
510 {
511  struct SREGS sreg;
512 
513  segread (&sreg);
514  return int386x (intno, ireg, oreg, &sreg);
515 }
516 
517 int int386x (int intno, union REGS *ireg, union REGS *oreg, struct SREGS *sreg)
518 {
519  static IREGS rm_reg;
520 
521  rm_reg.r_ss = rm_reg.r_sp = rm_reg.r_flags = 0;
522  rm_reg.r_ax = ireg->x.eax;
523  rm_reg.r_bx = ireg->x.ebx;
524  rm_reg.r_cx = ireg->x.ecx;
525  rm_reg.r_dx = ireg->x.edx;
526  rm_reg.r_si = ireg->x.esi;
527  rm_reg.r_di = ireg->x.edi;
528  rm_reg.r_ds = sreg->ds;
529  rm_reg.r_es = sreg->es;
530  rm_reg.r_gs = 0; /* needed? */
531  rm_reg.r_fs = 0; /* needed? */
532 
533  if (real_interrupt(intno,&rm_reg) < 0)
534  {
535  oreg->x.cflag |= 1; /* Set carry bit */
536  return (-1);
537  }
538  oreg->x.eax = rm_reg.r_ax;
539  oreg->x.ebx = rm_reg.r_bx;
540  oreg->x.ecx = rm_reg.r_cx;
541  oreg->x.edx = rm_reg.r_dx;
542  oreg->x.esi = rm_reg.r_si;
543  oreg->x.edi = rm_reg.r_di;
544  oreg->x.flags = rm_reg.r_flags;
545  return (int)rm_reg.r_ax;
546 }
547 
548 void segread (struct SREGS *sreg)
549 {
550  sreg->ds = MY_DS();
551  sreg->es = MY_ES();
552  sreg->ss = MY_SS();
553  sreg->cs = MY_CS();
554 }
555 #endif /* (DMC386 || MSC386 || BORLAND386) && !(DOSX & POWERPAK) */
556 
557 
558 #if (DOSX & DOS4GW) && defined(WATCOM386)
559 
560 #if defined(USE_EXCEPT_HANDLER)
561 
562 extern int _STACKTOP; /* internal variable, top of Watcom stack */
563 
564 /*
565  * Various contortions necessary to set CauseWay internal stack to
566  * Watcom DGROUP-based stack and to keep the unknown number of stack
567  * parameters relative to register EBP unchanged.
568  */
569 extern void SS_TO_DGROUP (void);
570 #pragma aux SS_TO_DGROUP = \
571  "sub ebp, esp" \
572  "xor eax, eax" \
573  "mov ax, ss" \
574  "mov es, ax" \
575  "mov ebx, esp" \
576  "mov edx, _STACKTOP" \
577  "mov cx, ds" \
578  "mov ss, cx" \
579  "mov esp, edx" \
580  "mov edx, esi" \
581  "mov edi, esi" \
582  "sub edi, ebx" \
583  "sub edx, 2" \
584  "looper: mov cx, es:[edx]" \
585  "sub esp, 2" \
586  "mov ss:[esp], cx" \
587  "sub edx, 2" \
588  "sub edi, 2" \
589  "jg looper" \
590  "add ebp, esp" \
591  "push eax" \
592  "push esi" \
593  modify [eax ebx ecx edx edi];
594 
595 extern void RESTORE_SS_AND_GO (void);
596 #pragma aux RESTORE_SS_AND_GO = \
597  "pop esi" \
598  "pop eax" \
599  "sub esi, 8" \
600  "mov ss, ax" \
601  "mov esp, esi" \
602  "retf";
603 
604 /*
605  * Termination routine MUST NOT have stack-checking enabled.
606  * If virtual memory is in use, this routine and all code and data called
607  * or used by the routine (including Watcom runtime library functions)
608  * must be locked in memory.
609  */
610 #include "nochkstk.h"
611 
612 static void far __loadds exception_main (void)
613 {
614  SS_TO_DGROUP();
615 
616  exc_struct.mode = (exc_struct.cs != MY_CS());
617 
618  if (user_exc_hook)
619  (*user_exc_hook) (&exc_struct);
620  else _printk ("Exception %d at CS:EIP %04X:%08X\n)",
621  exc_struct.fault_num, exc_struct.cs, exc_struct.eip);
622  RESTORE_SS_AND_GO();
623 }
624 #endif /* USE_EXCEPT_HANDLER */
625 
626 
629 static DWORD exc_app_start = 4096UL;
630 
631 /*
632  * Perform a stack trace back to CRT. Function arguments printed only
633  * for stack-based calls (-3s).
634  *
635  * \todo Merge this function with the one in x32vm.c.
636  */
637 void stack_rewind (DWORD start, DWORD base)
638 {
639  int loop = 10; /* print max 10 stack frames */
640  DWORD eip = start;
641  DWORD limit = get_cs_limit();
642  const DWORD *context = (const DWORD*) base; /* EBP increases as we rewind */
643  BOOL reg_calls = FALSE;
644 
645 #if defined(__SW_3R)
646  reg_calls = TRUE;
647 #endif
648 
649  _printk ("Stack trace:\r\n");
650 
651  while (context >= (DWORD*)base && ((DWORD)context & 3) == 0 && --loop)
652  {
653  const DWORD *next;
654 
655  if ((DWORD)context >= limit - 4 || eip >= limit ||
656  (DWORD)context <= exc_app_start || eip <= exc_app_start)
657  break;
658 
659  _printk (" %08X ", eip);
660 
661  next = (const DWORD*) *context; /* get ESP stack value from context */
662 
663  /* Compute number of args to display
664  */
665  if (next == NULL || /* we're rewound back to CRT */
666  next <= (const DWORD*)exc_app_start || reg_calls)
667  _printk ("( *** )");
668 
669  else
670  {
671  const DWORD *argv;
672  DWORD argc = next - context - 2;
673 
674  argc = (argc > 5) ? 5 : argc;
675  _printk ("(");
676 
677  argv = context + 2; /* Args start after saved EBP and return address */
678  while (argc--)
679  {
680  if (argc == 0)
681  _printk ("%04X)\r\n", *argv++);
682  else _printk ("%04X ", *argv++);
683  }
684  }
685  eip = *(context+1); /* get next return address */
686  context = next;
687  }
688  _printk ("\r\n");
689 }
690 #endif /* (DOSX & DOS4GW) && WATCOM386 */
691 #endif /* DOSX & (DOS4GW|POWERPAK) */
692 
693 
694 #if defined(WATCOM386)
695 BOOL dpmi_init (void)
696 {
697  switch (_Extender)
698  {
699  case DOSX_PHAR_V2: /* Test for Pharlap extenders */
700  case DOSX_PHAR_V3:
701  case DOSX_PHAR_V4:
702  case DOSX_PHAR_V5:
703  case DOSX_PHAR_V6:
704  case DOSX_PHAR_V7:
705  case DOSX_PHAR_V8:
706 #if (DOSX & PHARLAP)
707  return (TRUE);
708 #else
709  outsnl (_LANG("\7The Watt-32 library was not compiled for Pharlap."));
710  return (FALSE);
711 
712  case DOSX_RATIONAL:
713  if (_ExtenderSubtype & XS_RATIONAL_NONZEROBASE)
714  {
715  outsnl (_LANG("\7Only zero-based DOS4GW applications supported."));
716  return (FALSE);
717  }
718  break; /* okay */
719 #endif
720 
721  default:
722 #if (DOSX & PHARLAP)
723  outsnl (_LANG("\7Only Pharlap extenders supported"));
724 #else
725  outsnl (_LANG("\7Only DOS4GW style extenders supported"));
726 #endif
727  return (FALSE);
728  }
729  return (TRUE);
730 }
731 #endif /* WATCOM386 */
732 #endif /* __MSDOS__ */
733 
Core definitions.
static DWORD exc_app_start
Definition: wdpmi.c:629
Definition: esp.h:48
Definition: misc.h:511