Watt-32 tcp/ip  2.2 dev-rel.10
x32vm.c
Go to the documentation of this file.
1 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include "wattcp.h"
16 #include "printk.h"
17 #include "strings.h"
18 #include "misc.h"
19 #include "cpumodel.h"
20 #include "x32vm.h"
21 
22 #if (DOSX & X32VM) /* rest of file */
23 
24 #define MAX_WRAPPERS 32
25 #define MARKER 0xDEADBEEF
26 #define SEG_OFS_TO_LIN(s,o) ((DWORD)_x386_zero_base_ptr + \
27  (DWORD)(o) + ((DWORD)(s) << 4))
28 
29 typedef struct RMCB_record {
30  SWI_REGS rm_reg;
31  REALPTR dos_real;
32  REALPTR dos_para_addr;
33  UINT stack_size;
34  UINT *stack_bottom;
35  UINT *stack_top;
36  pmodeHook callback;
37  DWORD marker;
38  } RMCB_record;
39 
40 typedef enum {
41  RETF = 0xCB, /* far return */
42  IRET = 0xCF /* interrupt return */
43  } ReturnType;
44 
45 static char num_wrappers = 0;
46 static DWORD exc_app_start = 4096;
47 static struct RMCB_record rmcb [MAX_WRAPPERS];
48 
49 #if defined(DMC386)
50 
51 static void __far PmodeGlue (int taskIndex);
52 static void PmGlueEnd (void);
53 
54 void _dx_rmiv_get (int int_no, REALPTR *handler)
55 {
56  __asm {
57  mov eax, 2503h
58  mov ecx, int_no
59  int 21h
60  mov eax, handler
61  mov [eax], ebx
62  }
63 }
64 
65 void _dx_rmiv_set (int int_no, REALPTR handler)
66 {
67  __asm {
68  push ebx
69  mov eax, 2505h
70  mov ebx, handler
71  mov ecx, int_no
72  int 21h
73  pop ebx
74  }
75 }
76 
77 void _dx_pmiv_get (int int_no, FARPTR *handler)
78 {
79  __asm {
80  push es
81  push ebx
82  mov eax, 2502h
83  mov ecx, int_no
84  int 21h
85  mov eax, handler
86  mov [eax], ebx
87  mov [eax+4], es
88  pop ebx
89  pop es
90  }
91 }
92 
93 void _dx_apmiv_set (int int_no, FARPTR handler)
94 {
95  __asm {
96  push ds
97  mov edx, dword ptr handler[0]
98  mov ax, word ptr handler[2]
99  mov ds, ax
100  mov eax, 2506h
101  mov ecx, int_no
102  int 21h
103  pop ds
104  }
105 }
106 
107 void _dx_real_int (int int_no, SWI_REGS *regs)
108 {
109  RMI_BLK rmi;
110 
111  __asm {
112  push ebx
113  push esi
114  push edi
115  mov eax, int_no
116  mov rmi.inum, ax /* rmi.inum = int_no */
117 
118  mov eax, regs
119  mov cx, word ptr [eax].r_ds
120  mov rmi.ds_reg, cx /* rmi.ds_reg = regs->r_ds */
121 
122  mov cx, word ptr [eax].r_es
123  mov rmi.es_reg, cx /* rmi.es_reg = regs->r_es */
124 
125  mov ecx, [eax].r_ax
126  mov rmi.eax_reg, ecx /* rmi.eax_reg = regs->r_ax */
127 
128  mov ecx, [eax].r_dx
129  mov rmi.edx_reg, ecx /* rmi.edx_reg = regs->r_dx */
130 
131  mov ebx, [eax].r_bx
132  mov ecx, [eax].r_cx
133  mov edi, [eax].r_di
134  mov esi, [eax].r_si
135  mov eax, 2511h
136  lea edx, rmi
137  push ebp
138  int 21h /* X32VM function 2511h */
139  pop ebp
140 
141  push eax
142  mov eax, [regs]
143  pushfd
144  pop [eax].r_flags
145  mov [eax].r_bx, ebx
146  mov [eax].r_cx, ecx
147  mov [eax].r_di, edi
148  mov [eax].r_si, esi
149  pop [eax].r_ax
150  pop edi
151  pop esi
152  pop ebx
153  }
154  regs->r_ds = rmi.ds_reg;
155  regs->r_es = rmi.es_reg;
156  regs->r_dx = rmi.edx_reg;
157 }
158 
159 /*
160  * !! Doesn't work yet (only needed in pcintr.c which isn't tested).
161  */
162 int _dx_call_real (REALPTR proc, RMC_BLK *rm_reg, DWORD count, ...)
163 {
164  __asm {
165  push esi
166  push edi
167  push ebx
168  mov eax, 250Eh
169  mov ebx, proc
170  mov ecx, count
171  int 21h
172  pop ebx
173  pop edi
174  pop esi
175  jc fail
176  }
177  ARGSUSED (rm_reg);
178  return (1);
179 fail:
180  return (0);
181 }
182 
183 void _dx_rmlink_get (REALPTR *cback, REALPTR *rm_cbuf,
184  DWORD *rm_cbuf_size, void _far **pm_cbuf)
185 {
186  __asm {
187  push es
188  push esi
189  push ebx
190  mov ax, 250Dh
191  int 21h
192  mov esi, [cback]
193  mov [esi], eax
194  mov esi, [rm_cbuf]
195  mov [esi], ebx
196  mov esi, [rm_cbuf_size]
197  mov [esi], ecx
198  mov ebx, [pm_cbuf]
199  mov [ebx], edx
200  mov [ebx+4], es
201  pop ebx
202  pop esi
203  pop es
204  }
205 }
206 
207 /*
208  * A simplified version of Pharlap's 2537h function.
209  * - Allocate conventional memory above DOS data buffer.
210  */
211 int _dx_real_above (int para_count, WORD *para, WORD *largest)
212 {
213  REALPTR rp = _x32_real_alloc (16*para_count);
214 
215  if (largest)
216  *largest = 0;
217  if (!rp)
218  return (-1);
219  *para = RP_SEG (rp);
220  return (0);
221 }
222 
223 int _dx_real_free (WORD seg)
224 {
225  _x32_real_free (seg << 16);
226  return (0);
227 }
228 
229 /*
230  * A simplified version of Pharlap's 25C0h function.
231  * - Allocate conventional memory.
232  */
233 int _dx_real_alloc (int para_count, WORD *para, WORD *largest)
234 {
235  WORD seg = _x32_real_alloc (16*para_count);
236 
237  if (!seg)
238  return (-1);
239  *para = seg;
240  *largest = 0;
241  return (0);
242 }
243 
244 #elif defined(WATCOM386)
245 
246 extern void __far PmodeGlue (int task_index);
247 extern void PmGlueEnd (void);
248 
250 #endif
251 
252 int _dx_lock_pgs (const void _far *addr, int len)
253 {
254  return _x386_memlock ((void _far*)addr, len);
255 }
256 
257 int _dx_lock_pgsn (const void *addr, int len) /* addr must not be on stack */
258 {
259  return _x386_memlock (MK_FP(MY_DS(),addr), len);
260 }
261 
262 int _dx_ulock_pgsn (const void *addr, int len)
263 {
264  return _x386_memunlock (MK_FP(MY_DS(),addr), len);
265 }
266 
267 void ReadRealMem (void *buf, REALPTR rp, unsigned len)
268 {
269  const BYTE *src = (const BYTE*) SEG_OFS_TO_LIN (RP_SEG(rp), RP_OFF(rp));
270  memcpy (buf, src, len);
271 }
272 
273 void WriteRealMem (REALPTR rp, const void *src, int len)
274 {
275  BYTE *dest = (BYTE*) SEG_OFS_TO_LIN (RP_SEG(rp), RP_OFF(rp));
276  memcpy (dest, src, len);
277 }
278 
279 void FillRealMem (REALPTR rp, char val, int len)
280 {
281  BYTE *dest = (BYTE*) SEG_OFS_TO_LIN (RP_SEG(rp), RP_OFF(rp));
282  memset (dest, val, len);
283 }
284 
285 void PokeRealWord (REALPTR rp, WORD val)
286 {
287  WORD *dest = (WORD*) SEG_OFS_TO_LIN (RP_SEG(rp), RP_OFF(rp));
288  *dest = val;
289 }
290 
291 #ifdef __SW_3R
292 #error !? Cannot use this with reg-calls.
293 #endif
294 
295 void stack_rewind (DWORD start, DWORD base)
296 {
297  int loop = 10; /* print max 10 stack frames */
298  DWORD eip = start;
299  DWORD *context = (DWORD*) base; /* EBP increases as we rewind */
300  DWORD limit = get_cs_limit();
301 
302  _printk ("Stack trace:\r\n");
303 
304  while (context >= (DWORD*)base && ((DWORD)context & 3) == 0 && --loop)
305  {
306  DWORD *next;
307 
308  if ((DWORD)context >= limit - 4 || eip >= limit ||
309  (DWORD)context <= exc_app_start || eip <= exc_app_start)
310  break;
311 
312  _printk (" %08X ", eip);
313 
314  next = (DWORD*)*context; /* get ESP stack value from context */
315 
316  /* Compute number of args to display
317  */
318  if (next == NULL || /* we're rewound back to CRT */
319  next <= (DWORD*)exc_app_start)
320  _printk ("( *** )");
321 
322  else
323  {
324  DWORD *argv;
325  DWORD argc = next - context - 2;
326 
327  argc = (argc > 5) ? 5 : argc;
328  _printk ("(");
329 
330  argv = context + 2; /* Args start after saved EBP and return address */
331  while (argc--)
332  {
333  if (argc == 0)
334  _printk ("%04X)\r\n", *argv++);
335  else _printk ("%04X ", *argv++);
336  }
337  }
338  eip = *(context+1); /* get next return address */
339  context = next;
340  }
341  _printk ("\r\n");
342 }
343 
344 
345 /*
346  * Take a seg-x:ofs REALPTR and return a normalized seg-y:0 REALPTR
347  */
348 static REALPTR normalize (REALPTR rp)
349 {
350  WORD seg = RP_SEG (rp);
351  WORD ofs = RP_OFF (rp);
352  seg += (ofs >> 4);
353  if (ofs & 0xF)
354  seg++;
355  RP_SET (rp, 0, seg);
356  return (rp);
357 }
358 
359 static REALPTR _dx_alloc_rmode_wrapper (pmodeHook pmHook,
360  int len, int stack_size,
361  ReturnType returnType)
362 {
363  #define DOFS 0x22 /* offset of data section (tiny model) */
364  #define DSIZE 12 /* sizeof data section at wrapper end */
365 
366  static BYTE rm_wrapper[] =
367  {
368  0x06, /* 00 push es */
369  0x1E, /* 01 push ds */
370  0x0E, /* 02 push cs */
371  0x1F, /* 03 pop ds ; DS = CS */
372  0x66,0x60, /* 04 pushad */
373  0x66,0xFF,0x36,DOFS+8,0, /* 06 push dword ptr task_ptr */
374  0x66,0x6A,0, /* 0B push dword ptr 0 ; use default selectors */
375  0x6A,0, /* 0E push word ptr 0 ; */
376  0x66,0xFF,0x36,DOFS,0, /* 10 push dword ptr prot_glue */
377  0xFF,0x1E,DOFS+4,0, /* 15 call r2p_addr */
378  0x83,0xC4,14, /* 19 add sp,14 ; discard used stack */
379  0x66,0x61, /* 1C popad */
380  0x1F, /* 1E pop ds */
381  0x07, /* 1F pop es */
382  0xCB, /* 20 retf */
383  0x90, /* 21 nop */
384  0,0,0,0, /* 22+0 prot_glue dd ? */
385  0,0,0,0, /* 22+4 r2p_addr dd ? */
386  0,0,0,0 /* 22+8 task_ptr dd ? */
387  };
388 
389  BYTE _far *fp_wrapper;
390  UINT *stack, i;
391  REALPTR dos_real; /* allocated DOS memory */
392  REALPTR r2p_addr; /* address of real to pmode switch */
393  REALPTR dos_tb_real; /* rmode-address of transfer buffer */
394  void _far *dos_tb_addr; /* ditto for pmode */
395  DWORD dos_tb_size; /* size of transfer buffer */
396 
397  WATT_ASSERT (sizeof(rm_wrapper) == DOFS+DSIZE);
398 
399  if (!pmHook || num_wrappers == MAX_WRAPPERS)
400  return (0);
401 
402  stack_size += sizeof(UINT) + 3; /* add one for marker and round up */
403  stack_size &= ~3;
404  stack = malloc (stack_size);
405  if (!stack)
406  return (0);
407 
408  len += sizeof(rm_wrapper) + 16;
409  dos_real = _x32_real_alloc (len);
410  if (!dos_real)
411  {
412  free (stack);
413  return (0);
414  }
415 
416  _dx_rmlink_get (&r2p_addr, &dos_tb_real, &dos_tb_size, &dos_tb_addr);
417 
418  for (i = 0; i < MAX_WRAPPERS; i++)
419  if (!rmcb[i].dos_real)
420  break;
421 
422  *(DWORD*) (rm_wrapper+DOFS+0) = (DWORD)&PmodeGlue; /* pmode helper */
423  *(DWORD*) (rm_wrapper+DOFS+4) = r2p_addr; /* rm->pm addr */
424  *(DWORD*) (rm_wrapper+DOFS+8) = (DWORD)(rmcb + i); /* task_ptr */
425  rm_wrapper [0x20] = returnType; /* RETF or IRET */
426 
427  /* lock pages used by callback
428  */
429  fp_wrapper = MK_FP (_x32_zero_base_selector, RP_SEG(dos_real) << 4);
430  _dx_lock_pgs (fp_wrapper, len);
431  _dx_lock_pgsn ((void*)&PmodeGlue, (UINT)&PmGlueEnd - (UINT)&PmodeGlue);
432  _dx_lock_pgsn ((void*)stack, stack_size);
433 
434  rmcb [i].dos_real = dos_real;
435  rmcb [i].callback = pmHook;
436  rmcb [i].stack_bottom = stack;
437  rmcb [i].stack_size = stack_size;
438  rmcb [i].stack_top = stack + stack_size/sizeof(UINT) - sizeof(UINT);
439  rmcb [i].stack_top[1] = MARKER;
440  rmcb [i].marker = MARKER;
441  rmcb [i].dos_para_addr = normalize (dos_real);
442  WriteRealMem (rmcb[i].dos_para_addr, &rm_wrapper, sizeof(rm_wrapper));
443 
444 #if 0
445  printf ("dos_real %08lX, r2p-addr %08lX, stack %08X\n",
446  dos_real, r2p_addr, stack);
447 #endif
448 
449  num_wrappers++;
450  return (rmcb[i].dos_para_addr);
451 }
452 
453 void _dx_free_rmode_wrapper (REALPTR dos_addr)
454 {
455  int i;
456 
457  for (i = 0; i < MAX_WRAPPERS; i++)
458  {
459  struct RMCB_record *tr = rmcb + i;
460 
461  if (!rmcb[i].dos_real || rmcb[i].dos_para_addr != dos_addr)
462  continue;
463 
464  if (tr->marker == MARKER)
465  _x32_real_free (tr->dos_real);
466 
467  if (tr->stack_top[1] == MARKER)
468  free (tr->stack_bottom);
469  memset (tr, 0, sizeof(*tr));
470  }
471 }
472 
473 REALPTR _dx_alloc_rmode_wrapper_retf (pmodeHook pmHook, rmodeHook rmHook,
474  int len, int stack_size)
475 {
476  ARGSUSED (rmHook);
477  return _dx_alloc_rmode_wrapper (pmHook, len, stack_size, RETF);
478 }
479 
480 REALPTR _dx_alloc_rmode_wrapper_iret (pmodeHook pmHook, int stack_size)
481 {
482  return _dx_alloc_rmode_wrapper (pmHook, 0, stack_size, IRET);
483 }
484 
485 #if defined(DMC386)
486 
487 static void __far PmodeGlue (struct RMCB_record *task_ptr)
488 {
489 /*
490  * We need an assembly language "glue" routine on the protected mode side
491  * to deal with several things:
492  * 1. It gets called with a FAR procedure call.
493  * 2. Copy all real-mode registers into the 'rm_reg' structure of the
494  * correct task-index.
495  * 3. Switch back to a stack in the data segment.
496  * 4. Call the HLL prot-mode callback with '&rm_reg' on stack.
497  * 5. Switch back to the stack DOSX has allocated for us.
498  * 6. Copy 'rm_reg' back onto the stack.
499  *
500  * Doesn't store ESP/EBP/FS/GS to SWI_REGS (not needed in Watt-32)
501  */
502 
503  __asm {
504  mov ebx, task_ptr
505  pushfd
506  push gs
507  push fs
508 
509 /*
510  * fill the 'rm_reg' struct based on the "pushad" instruction and the
511  * "push ds/es" of the wrapper. Registers that haven't changed are
512  * stored as-is.
513  *
514  * in wrapper: PUSH ES */ #define REG_ES [ebp+50]
515 /* PUSH DS */ #define REG_DS [ebp+48]
516 /* (PUSHAD) PUSH EAX */ #define REG_EAX [ebp+44]
517 /* PUSH ECX */ #define REG_ECX [ebp+40]
518 /* PUSH EDX */ #define REG_EDX [ebp+36]
519 /* PUSH EBX */ #define REG_EBX [ebp+32]
520 /* PUSH ESP */ #define REG_ESP [ebp+28]
521 /* PUSH EBP */ #define REG_EBP [ebp+24]
522 /* PUSH ESI */ #define REG_ESI [ebp+20]
523 /* PUSH EDI */ #define REG_EDI [ebp+16]
524 /* */
525 /* PUSH dword ptr task_ptr */
526 /* PUSH dword ptr 0 */
527 /* PUSH word ptr 0 */
528 /* PUSH dword ptr prot_glue */
529 
530  mov [ebx].r_ax, eax
531  mov [ebx].r_cx, ecx
532  mov [ebx].r_dx, edx
533  mov [ebx].r_si, esi
534  mov [ebx].r_di, edi
535 
536 #if 0 /* test */
537  movzx eax, word ptr REG_DS
538  push eax
539  call dhex4int /* print DS */
540  add esp, 4
541 
542  movzx eax, word ptr REG_ES
543  push eax
544  call dhex4int /* print ES */
545  add esp, 4
546 
547  mov ax, ss
548  movzx eax, ax
549  push eax
550  call dhex4int /* print SS */
551  add esp, 4
552 #endif
553 
554  pushfd
555  pop eax
556  mov [ebx].r_flags, eax
557 
558  mov eax, REG_EBX
559  mov [ebx].r_bx, eax
560 
561  mov eax, REG_DS
562  mov [ebx].r_ds, ax
563 
564  mov eax, REG_ES
565  mov [ebx].r_es, ax
566 
567  mov eax, [ebx].stack_bottom
568  push _x386_stacklow
569  mov _x386_stacklow, eax /* set new stack-low value */
570 
571  mov dx, ss
572  mov esi, esp /* DX:ESI = current SS:ESP */
573  mov ax, ds
574  mov ss, ax
575  mov esp, [ebx].stack_top /* new SS:ESP = DS:top-of-task-stack */
576 
577  push edx /* save old stack pointer on top */
578  push esi /* of new stack */
579 
580  push ebx /* because rm_reg is first in the structure */
581  cld /* C code need direction flag off */
582  call [ebx].callback /* call the C handler function */
583  lss esp, [esp+4] /* switch back to original stack */
584  pop _x386_stacklow
585 
586 /* fill stack with the rm_reg struct based on the "popad" instruction
587  * and the "pop ds/es" of the wrapper.
588  */
589  mov ax, [ebx].r_es
590  mov REG_ES, ax
591 
592  mov ax, [ebx].r_ds
593  mov REG_DS, ax
594 
595  mov eax, [ebx].r_ax
596  mov REG_EAX, eax
597 
598  mov eax, [ebx].r_cx
599  mov REG_ECX, eax
600 
601  mov eax, [ebx].r_dx
602  mov REG_EDX, eax
603 
604  mov eax, [ebx].r_bx
605  mov REG_EBX, eax
606 
607  mov eax, [ebx].r_si
608  mov REG_ESI, eax
609 
610  mov eax, [ebx].r_di
611  mov REG_EDI, eax
612 
613  pop fs
614  pop gs
615  popfd
616  }
617 }
618 
619 static void PmGlueEnd (void) /* end of area to lock */
620 {
621 }
622 #endif /* DMC386 */
623 #endif /* DOSX & X32VM */
624 
Core definitions.
Definition: x32vm.h:41
Definition: x32vm.h:30
Definition: if.h:83
static void PmGlueEnd(void)
Definition: x32vm.c:619
Definition: x32vm.h:16
static DWORD exc_app_start
Definition: wdpmi.c:629
Definition: esp.h:48
int _dx_real_alloc(int para_count, WORD *para, WORD *largest)
Definition: x32vm.c:233
static struct RMCB_record rmcb[MAX_WRAPPERS]
Definition: x32vm.c:47