Release 950302
[wine] / if1632 / call.S
1 /*
2  * Copyright  Robert J. Amstadt, 1993
3  */
4 #ifdef linux
5 #define UDATASEL 0x2b
6 #endif
7 #if defined(__NetBSD__) || defined(__FreeBSD__)
8 #define UDATASEL 0x27
9 #endif
10 #ifdef __ELF__
11 #define A(addr) addr
12 #else
13 #define A(addr) _##addr
14 #endif
15         .data
16 jump_target:
17 return_value:
18         .long   0
19
20 /**********************************************************************
21  *      Places to keep info about the current 32-bit stack frame.
22  */
23         .globl  A( IF1632_Saved32_esp), A(IF1632_Saved32_ebp), A(IF1632_Saved32_ss)
24 A(IF1632_Saved32_esp:)
25         .long   0
26 A(IF1632_Saved32_ebp:)
27         .long   0
28 A(IF1632_Saved32_ss:)
29         .word   0
30 #ifdef __ELF__
31 A(IF1632_ELF_KLUDGE:)
32         .long   0
33         .word   0x0f
34 #endif
35
36 /**********************************************************************
37  *      Places to keep info about the current 16-bit stack frame.
38  */
39         .globl A(IF1632_Saved16_sp),A(IF1632_Saved16_bp),A(IF1632_Saved16_ss)
40 A(IF1632_Saved16_sp:)
41         .word   0
42 A(IF1632_Saved16_bp:)
43         .word   0
44 A(IF1632_Saved16_ss:)
45         .word   0
46
47 nbytes:
48         .word   0
49 selector:
50         .word   0
51 offset:
52         .word   0
53
54         .text
55 \f
56 /**********************************************************************
57  *      int CallToInit16(unsigned long csip, unsigned long sssp,
58  *                   unsigned short ds)
59  *
60  *      Stack:          0       ebp
61  *                      4       eip
62  *                      8       target ip
63  *                      10      target cs
64  *                      12      target sp
65  *                      14      target ss
66  *                      16      target ds
67  */
68         .align  4
69         .globl A(CallToInit16)
70 A(CallToInit16:)
71         pushl   %ebp
72         movl    %esp,%ebp
73
74         /*
75          * Save our registers
76          */
77         pushal
78         pushl   A(IF1632_Saved32_esp)
79         pushl   A(IF1632_Saved32_ebp)
80         pushw   A(IF1632_Saved32_ss)
81
82 #ifdef __ELF__
83         /* change to the other code segment */
84         movw    $0x0f, %ax
85         movw    %ax, A(IF1632_ELF_KLUDGE)+4
86         movl    $L4, %eax
87         andl    $0x0000ffff, %eax
88         movl    %eax,A(IF1632_ELF_KLUDGE)
89         ljmp    A(IF1632_ELF_KLUDGE)
90 L4:
91 #endif
92         /*
93          * Get target address.
94          */
95         movl    8(%ebp),%eax
96         movl    %eax,jump_target
97         lea     jump_target,%edx
98
99         /*
100          * Put stack registers where we can get them after stack switch.
101          */
102         movw    %ss,A(IF1632_Saved32_ss)
103         movl    %esp,A(IF1632_Saved32_esp)
104         movl    %ebp,A(IF1632_Saved32_ebp)
105
106         /*
107          * Load initial registers
108          */
109         movw    A(WIN_StackSize),%bx
110         movw    A(WIN_HeapSize),%cx
111         movl    $0,%esi
112         xorl    %eax,%eax
113         movw    A(PSPSelector),%ax
114         movw    %ax,%es
115         movw    16(%ebp),%ax
116         movw    %ax,%ds
117         movl    %eax,%edi
118         xorl    %eax,%eax
119         movw    12(%ebp),%ax
120         movl    %eax,%esp
121         movw    14(%ebp),%ax
122         movw    %ax,%ss
123         movl    %esp,%eax
124         movl    %eax,%ebp
125         movw    $UDATASEL,%ax
126         movw    %ax,%fs
127         movw    %ax,%gs
128         movw    %ds,%ax
129
130         /*
131          * Call entry point
132          */
133         .byte   0x66
134         lcall   %fs:(%edx)
135 \f
136         /*
137          * Restore old stack and segment registers.
138          *
139          * Two choices here:
140          *      1. Trust that fs or gs hasn't changed.
141          *      2. Rely on knowledge of Linux use of segments.
142          *
143          * I'll opt for choice 2 because who knows what programs we
144          * going to run.  Linux should be fairly stable in terms of
145          * GDT usage.
146          */
147         pushl   %eax
148         movw    $UDATASEL,%ax
149         movw    %ax,%ds
150         movw    %ax,%es
151         movw    %ax,%fs
152         movw    %ax,%gs
153         popl    %eax
154         movw    A(IF1632_Saved32_ss),%ss
155         movl    A(IF1632_Saved32_esp),%esp
156         movl    A(IF1632_Saved32_ebp),%ebp
157
158         /*
159          * Restore registers, but do not destroy return value.
160          */
161         popw    A(IF1632_Saved32_ss)
162         popl    A(IF1632_Saved32_ebp)
163         popl    A(IF1632_Saved32_esp)
164         movl    %eax,return_value
165 #ifdef __ELF__
166         /* change back  */
167         movw    $0x23, %ax
168         movw    %ax, A(IF1632_ELF_KLUDGE)+4
169         movl    $L5, %eax
170         movl    %eax,A(IF1632_ELF_KLUDGE)
171         ljmp    A(IF1632_ELF_KLUDGE)
172 L5:
173 #endif
174         popal
175         movl    return_value,%eax
176         .align  2,0x90
177         leave
178         ret
179 \f
180 /**********************************************************************
181  *      int CallTo16  (unsigned long csip, unsigned short ds)
182  *      int CallTo16cx(unsigned long csip, unsigned long dscx);
183  *
184  *      Stack:          0       ebp
185  *                      4       eip
186  *                      8       target ip
187  *                      10      target cs
188  *                      12      target ds
189  *                      14      target cx  (only CallTo16cx)
190  *                      16      target di
191  */
192         .align  4
193         .globl A(CallTo16), A(CallTo16cx), A(CallToLibMain)
194 A(CallToLibMain:)
195         pushl   %ebp
196         movl    %esp,%ebp
197         movw    16(%ebp),%di
198         movw    0,%si
199         movw    0,%es
200         jmp     L1
201 A(CallTo16:)
202 A(CallTo16cx:)
203         pushl   %ebp
204         movl    %esp,%ebp
205
206         /*
207          * Get target address and new ds
208          */
209 L1:
210 #ifdef __ELF__
211         /* change code segments */
212         movw    $0x0f, %ax
213         movw    %ax, A(IF1632_ELF_KLUDGE)+4
214         movl    $L2, %eax
215         andl    $0x0000ffff, %eax
216         movl    %eax,A(IF1632_ELF_KLUDGE)
217         ljmp    A(IF1632_ELF_KLUDGE)
218 L2:
219 #endif
220         /* At this point we have changed segments. */
221         movl    8(%ebp),%eax
222         movl    %eax,jump_target
223         lea     jump_target,%edx
224         movw    12(%ebp),%ax
225         movw    14(%ebp),%cx
226
227         /*
228          * Switch to 16-bit stack
229          */
230         pushl   A(IF1632_Saved32_esp)
231         pushl   A(IF1632_Saved32_ebp)
232         pushw   A(IF1632_Saved32_ss)
233
234         movw    %ss,A(IF1632_Saved32_ss)
235         movl    %esp,A(IF1632_Saved32_esp)
236         movl    %ebp,A(IF1632_Saved32_ebp)
237
238         movw    A(IF1632_Saved16_ss),%ss
239         movw    A(IF1632_Saved16_sp),%sp
240         movw    A(IF1632_Saved16_bp),%bp
241
242         /*
243          * Call entry point
244          */
245         movw    %ax,%ds
246         movw    %ax,%di
247         .byte   0x66
248         lcall   %fs:(%edx)
249 \f
250         /*
251          * Restore old stack and segment registers.
252          *
253          * Two choices here:
254          *      1. Trust that fs or gs hasn't changed.
255          *      2. Rely on knowledge of Linux use of segments.
256          *
257          * I'll opt for choice 2 because who knows what programs we
258          * going to run.  Linux should be fairly stable in terms of
259          * GDT usage.
260          */
261         pushl   %eax
262         movw    $UDATASEL,%ax
263         movw    %ax,%ds
264         movw    %ax,%es
265         movw    %ax,%fs
266         movw    %ax,%gs
267         popl    %eax
268
269         movw    %ss,A(IF1632_Saved16_ss)
270         movw    %esp,A(IF1632_Saved16_sp)
271         movw    %ebp,A(IF1632_Saved16_bp)
272
273         movw    A(IF1632_Saved32_ss),%ss
274         movl    A(IF1632_Saved32_esp),%esp
275         movl    A(IF1632_Saved32_ebp),%ebp
276
277         popw    A(IF1632_Saved32_ss)
278         popl    A(IF1632_Saved32_ebp)
279         popl    A(IF1632_Saved32_esp)
280
281         movl    %eax,return_value
282         movw    return_value+2,%dx
283         /* switch segments */
284 #ifdef __ELF__
285         movw    $0x23, %ax
286         movw    %ax, A(IF1632_ELF_KLUDGE)+4
287         movl    $L3, %eax
288         movl    %eax,A(IF1632_ELF_KLUDGE)
289         ljmp    A(IF1632_ELF_KLUDGE)
290 L3:
291         /* back in the regular segment set up. */
292         /* restore eax */
293         movl    return_value, %eax
294 #endif
295         .align  2,0x90
296         leave
297         ret
298 \f
299 /**********************************************************************
300  *      CallTo32()
301  *
302  *      This function is called as a relay point to the built function
303  *      handler.  KERNEL, USER and GDI calls are dealt with by this
304  *      handler.  Calls to these DLLs will be mapped to a call handler
305  *      which will set EAX to a number indicating which DLL and which
306  *      function within that DLL.
307  *
308  *      This function will pass to the function handler two arguments.
309  *      The first argument will be the contents of EAX, the second
310  *      argument will be a segment:offset pair that points to the
311  *      16-bit stack.
312  */
313         .align  4
314         .globl A(CallTo32)
315 A(CallTo32:)
316         andl    $0x0000ffff,%esp
317         pushw   %bp
318         movl    %esp,%ebp
319
320         /*
321          * Save registers.  286 mode does not have fs or gs.
322          */
323         pushw   %ds
324         pushw   %es
325
326         /*
327          * Restore segment registers.
328          */
329         pushl   %eax
330         movw    $UDATASEL,%ax
331         movw    %ax,%ds
332         movw    %ax,%es
333         popl    %eax
334
335         /*
336          * Save old stack save variables, save stack registers, reload
337          * stack registers.
338          */
339         pushw   A(IF1632_Saved16_sp)
340         pushw   A(IF1632_Saved16_bp)
341         pushw   A(IF1632_Saved16_ss)
342
343         movw    %ss,A(IF1632_Saved16_ss)
344         movw    %sp,A(IF1632_Saved16_sp)
345         movw    %bp,A(IF1632_Saved16_bp)
346
347         movw    A(IF1632_Saved32_ss),%ss
348         movl    A(IF1632_Saved32_esp),%esp
349         movl    A(IF1632_Saved32_ebp),%ebp
350
351         /*
352          * Call entry point
353          */
354         pushl   %edx
355         pushw   A(IF1632_Saved16_ss)
356         pushw   A(IF1632_Saved16_sp)
357         pushl   %eax
358         call    A(DLLRelay)
359 \f
360         popl    %edx
361         popl    %edx
362         popl    %edx
363
364         /*
365          * Restore registers, but do not destroy return value.
366          */
367         movw    A(IF1632_Saved16_ss),%ss
368         movw    A(IF1632_Saved16_sp),%sp
369         movw    A(IF1632_Saved16_bp),%bp
370
371         popw    A(IF1632_Saved16_ss)
372         popw    A(IF1632_Saved16_bp)
373         popw    A(IF1632_Saved16_sp)
374
375         popw    %es
376         popw    %ds
377         popw    %bp
378
379         /*
380          * Now we need to ditch the parameter bytes that were left on the
381          * stack. We do this by effectively popping the number of bytes,
382          * and the return address, removing the parameters and then putting
383          * the return address back on the stack.
384          * Normally this field is filled in by the relevant function in
385          * the emulation library, since it should know how many bytes to
386          * expect.
387          */
388         popw    %gs:nbytes
389         cmpw    $0,%gs:nbytes
390         je      noargs
391         popw    %gs:offset
392         popw    %gs:selector
393         addw    %gs:nbytes,%esp
394         pushw   %gs:selector
395         pushw   %gs:offset
396 noargs:
397
398         /*
399          * Last, but not least we need to move the high word from eax to dx
400          */
401
402         pushl   %eax
403         popw    %dx
404         popw    %dx
405
406         .byte   0x66
407         lret
408 \f
409 /**********************************************************************
410  *      CallTo32_16()
411  *
412  *      This function is same one as CallTo32() except that the high
413  *      word of EAX won't be moved to DX.
414  */
415         .align  4
416         .globl A(CallTo32_16)
417 A(CallTo32_16:)
418         andl    $0x0000ffff,%esp
419         pushw   %bp
420         movl    %esp,%ebp
421
422         /*
423          * Save registers.  286 mode does not have fs or gs.
424          */
425         pushw   %ds
426         pushw   %es
427
428         /*
429          * Restore segment registers.
430          */
431         pushl   %eax
432         movw    $UDATASEL,%ax
433         movw    %ax,%ds
434         movw    %ax,%es
435         popl    %eax
436
437         /*
438          * Save old stack save variables, save stack registers, reload
439          * stack registers.
440          */
441         pushw   A(IF1632_Saved16_sp)
442         pushw   A(IF1632_Saved16_bp)
443         pushw   A(IF1632_Saved16_ss)
444
445         movw    %ss,A(IF1632_Saved16_ss)
446         movw    %esp,A(IF1632_Saved16_sp)
447         movw    %ebp,A(IF1632_Saved16_bp)
448
449         movw    A(IF1632_Saved32_ss),%ss
450         movl    A(IF1632_Saved32_esp),%esp
451         movl    A(IF1632_Saved32_ebp),%ebp
452
453         /*
454          * Call entry point
455          */
456         pushl   %edx
457         pushw   A(IF1632_Saved16_ss)
458         pushw   A(IF1632_Saved16_sp)
459         pushl   %eax
460         call    A(DLLRelay)
461 \f
462         popl    %edx
463         popl    %edx
464         popl    %edx
465
466         /*
467          * Restore registers, but do not destroy return value.
468          */
469         movw    A(IF1632_Saved16_ss),%ss
470         movw    A(IF1632_Saved16_sp),%sp
471         movw    A(IF1632_Saved16_bp),%bp
472
473         popw    A(IF1632_Saved16_ss)
474         popw    A(IF1632_Saved16_bp)
475         popw    A(IF1632_Saved16_sp)
476
477         popw    %es
478         popw    %ds
479         popw    %bp
480
481         /*
482          * Now we need to ditch the parameter bytes that were left on the
483          * stack. We do this by effectively popping the number of bytes,
484          * and the return address, removing the parameters and then putting
485          * the return address back on the stack.
486          * Normally this field is filled in by the relevant function in
487          * the emulation library, since it should know how many bytes to
488          * expect.
489          */
490         popw    %gs:nbytes
491         cmpw    $0,%gs:nbytes
492         je      noargs2
493         popw    %gs:offset
494         popw    %gs:selector
495         addw    %gs:nbytes,%esp
496         pushw   %gs:selector
497         pushw   %gs:offset
498 noargs2:
499         .byte   0x66
500         lret
501 \f
502 /**********************************************************************
503  *      ReturnFromRegisterFunc()
504  */
505         .globl A(ReturnFromRegisterFunc)
506 A(ReturnFromRegisterFunc:)
507         /*
508          * Restore 16-bit stack
509          */
510         movw    A(IF1632_Saved16_ss),%ss
511         movw    A(IF1632_Saved16_sp),%sp
512         movw    A(IF1632_Saved16_bp),%bp
513
514         popw    A(IF1632_Saved16_ss)
515         popw    A(IF1632_Saved16_bp)
516         popw    A(IF1632_Saved16_sp)
517
518         popw    %es
519         popw    %ds
520         popw    %bp
521
522         /*
523          * This leaves us with a stack that has number of arguments,
524          * the return address, the saved registers, and the return 
525          * address again.
526          */
527         add     $6,%esp         /* argument count, return address */
528 #include "pop.h"                /* restore context                */
529
530         /*
531          * Return to original caller.
532          */
533         .byte   0x66
534         lret
535