Release 940722
[wine/hacks.git] / if1632 / call.S
blob48f6d759f3bc51a63669953fc749103db232e19b
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         .data
11 jump_target:
12 return_value:
13         .long   0
15 /**********************************************************************
16  *      Places to keep info about the current 32-bit stack frame.
17  */
18         .globl  _IF1632_Saved32_esp,_IF1632_Saved32_ebp,_IF1632_Saved32_ss
19 _IF1632_Saved32_esp:
20         .long   0
21 _IF1632_Saved32_ebp:
22         .long   0
23 _IF1632_Saved32_ss:
24         .word   0
26 /**********************************************************************
27  *      Places to keep info about the current 16-bit stack frame.
28  */
29         .globl  _IF1632_Saved16_esp,_IF1632_Saved16_ebp,_IF1632_Saved16_ss
30 _IF1632_Saved16_esp:
31         .long   0
32 _IF1632_Saved16_ebp:
33         .long   0
34 _IF1632_Saved16_ss:
35         .word   0
37 nbytes:
38         .word   0
39 selector:
40         .word   0
41 offset:
42         .word   0
44         .text
46 /**********************************************************************
47  *      int CallToInit16(unsigned long csip, unsigned long sssp,
48  *                   unsigned short ds)
49  *
50  *      Stack:          0       ebp
51  *                      4       eip
52  *                      8       target ip
53  *                      10      target cs
54  *                      12      target sp
55  *                      14      target ss
56  *                      16      target ds
57  */
58         .align  4
59         .globl _CallToInit16
60 _CallToInit16:
61         pushl   %ebp
62         movl    %esp,%ebp
64         /*
65          * Save our registers
66          */
67         pushal
68         pushl   _IF1632_Saved32_esp
69         pushl   _IF1632_Saved32_ebp
70         pushw   _IF1632_Saved32_ss
72         /*
73          * Get target address.
74          */
75         movl    8(%ebp),%eax
76         movl    %eax,jump_target
77         lea     jump_target,%edx
79         /*
80          * Put stack registers where we can get them after stack switch.
81          */
82         movw    %ss,_IF1632_Saved32_ss
83         movl    %esp,_IF1632_Saved32_esp
84         movl    %ebp,_IF1632_Saved32_ebp
86         /*
87          * Load initial registers
88          */
89         movw    _WIN_StackSize,%bx
90         movw    _WIN_HeapSize,%cx
91         movl    $0,%esi
92         xorl    %eax,%eax
93         movw    _PSPSelector,%ax
94         movw    %ax,%es
95         movw    16(%ebp),%ax
96         movw    %ax,%ds
97         movl    %eax,%edi
98         xorl    %eax,%eax
99         movw    12(%ebp),%ax
100         movl    %eax,%esp
101         movw    14(%ebp),%ax
102         movw    %ax,%ss
103         movl    %esp,%eax
104         movl    %eax,%ebp
105         movw    $UDATASEL,%ax
106         movw    %ax,%fs
107         movw    %ax,%gs
108         movw    %ds,%ax
110         /*
111          * Call entry point
112          */
113         .byte   0x66
114         lcall   %fs:(%edx)
116         /*
117          * Restore old stack and segment registers.
118          *
119          * Two choices here:
120          *      1. Trust that fs or gs hasn't changed.
121          *      2. Rely on knowledge of Linux use of segments.
122          *
123          * I'll opt for choice 2 because who knows what programs we
124          * going to run.  Linux should be fairly stable in terms of
125          * GDT usage.
126          */
127         pushl   %eax
128         movw    $UDATASEL,%ax
129         movw    %ax,%ds
130         movw    %ax,%es
131         movw    %ax,%fs
132         movw    %ax,%gs
133         popl    %eax
134         movw    _IF1632_Saved32_ss,%ss
135         movl    _IF1632_Saved32_esp,%esp
136         movl    _IF1632_Saved32_ebp,%ebp
138         /*
139          * Restore registers, but do not destroy return value.
140          */
141         popw    _IF1632_Saved32_ss
142         popl    _IF1632_Saved32_ebp
143         popl    _IF1632_Saved32_esp
144         movl    %eax,return_value
145         popal
146         movl    return_value,%eax
147         .align  2,0x90
148         leave
149         ret
151 /**********************************************************************
152  *      int CallTo16(unsigned long csip, unsigned short ds)
154  *      Stack:          0       ebp
155  *                      4       eip
156  *                      8       target ip
157  *                      10      target cs
158  *                      12      target ds
159  */
160         .align  4
161         .globl _CallTo16
162 _CallTo16:
163         pushl   %ebp
164         movl    %esp,%ebp
166         /*
167          * Get target address and new ds
168          */
169         movl    8(%ebp),%eax
170         movl    %eax,jump_target
171         lea     jump_target,%edx
172         movw    12(%ebp),%ax
174         /*
175          * Switch to 16-bit stack
176          */
177         pushl   _IF1632_Saved32_esp
178         pushl   _IF1632_Saved32_ebp
179         pushw   _IF1632_Saved32_ss
181         movw    %ss,_IF1632_Saved32_ss
182         movl    %esp,_IF1632_Saved32_esp
183         movl    %ebp,_IF1632_Saved32_ebp
185         movw    _IF1632_Saved16_ss,%ss
186         movl    _IF1632_Saved16_esp,%esp
187         movl    _IF1632_Saved16_ebp,%ebp
189         /*
190          * Call entry point
191          */
192         movw    %ax,%ds
193         movw    %ax,%di
194         .byte   0x66
195         lcall   %fs:(%edx)
197         /*
198          * Restore old stack and segment registers.
199          *
200          * Two choices here:
201          *      1. Trust that fs or gs hasn't changed.
202          *      2. Rely on knowledge of Linux use of segments.
203          *
204          * I'll opt for choice 2 because who knows what programs we
205          * going to run.  Linux should be fairly stable in terms of
206          * GDT usage.
207          */
208         pushl   %eax
209         movw    $UDATASEL,%ax
210         movw    %ax,%ds
211         movw    %ax,%es
212         movw    %ax,%fs
213         movw    %ax,%gs
214         popl    %eax
216         movw    %ss,_IF1632_Saved16_ss
217         movl    %esp,_IF1632_Saved16_esp
218         movl    %ebp,_IF1632_Saved16_ebp
220         movw    _IF1632_Saved32_ss,%ss
221         movl    _IF1632_Saved32_esp,%esp
222         movl    _IF1632_Saved32_ebp,%ebp
224         popw    _IF1632_Saved32_ss
225         popl    _IF1632_Saved32_ebp
226         popl    _IF1632_Saved32_esp
228         movl    %eax,return_value
229         movw    return_value+2,%dx
230         .align  2,0x90
231         leave
232         ret
234 /**********************************************************************
235  *      CallTo32()
237  *      This function is called as a relay point to the built function
238  *      handler.  KERNEL, USER and GDI calls are dealt with by this
239  *      handler.  Calls to these DLLs will be mapped to a call handler
240  *      which will set EAX to a number indicating which DLL and which
241  *      function within that DLL.
243  *      This function will pass to the function handler two arguments.
244  *      The first argument will be the contents of EAX, the second
245  *      argument will be a segment:offset pair that points to the
246  *      16-bit stack.
247  */
248         .align  4
249         .globl _CallTo32
250 _CallTo32:
251         pushl   %ebp
252         movl    %esp,%ebp
254         /*
255          * Save registers.  286 mode does not have fs or gs.
256          */
257         pushw   %ds
258         pushw   %es
260         /*
261          * Restore segment registers.
262          */
263         pushl   %eax
264         movw    $UDATASEL,%ax
265         movw    %ax,%ds
266         movw    %ax,%es
267         popl    %eax
269         /*
270          * Save old stack save variables, save stack registers, reload
271          * stack registers.
272          */
273         pushl   _IF1632_Saved16_esp
274         pushl   _IF1632_Saved16_ebp
275         pushw   _IF1632_Saved16_ss
277         movw    %ss,_IF1632_Saved16_ss
278         movl    %esp,_IF1632_Saved16_esp
279         movl    %ebp,_IF1632_Saved16_ebp
281         movw    _IF1632_Saved32_ss,%ss
282         movl    _IF1632_Saved32_esp,%esp
283         movl    _IF1632_Saved32_ebp,%ebp
285         /*
286          * Call entry point
287          */
288         pushl   %edx
289         pushw   _IF1632_Saved16_ss
290         pushw   _IF1632_Saved16_esp
291         pushl   %eax
292         call    _DLLRelay
294         popl    %edx
295         popl    %edx
296         popl    %edx
298         /*
299          * Restore registers, but do not destroy return value.
300          */
301         movw    _IF1632_Saved16_ss,%ss
302         movl    _IF1632_Saved16_esp,%esp
303         movl    _IF1632_Saved16_ebp,%ebp
305         popw    _IF1632_Saved16_ss
306         popl    _IF1632_Saved16_ebp
307         popl    _IF1632_Saved16_esp
309         popw    %es
310         popw    %ds
312         .align  2,0x90
313         leave
314         /*
315          * Now we need to ditch the parameter bytes that were left on the
316          * stack. We do this by effectively popping the number of bytes,
317          * and the return address, removing the parameters and then putting
318          * the return address back on the stack.
319          * Normally this field is filled in by the relevant function in
320          * the emulation library, since it should know how many bytes to
321          * expect.
322          */
323         popw    %gs:nbytes
324         cmpw    $0,%gs:nbytes
325         je      noargs
326         popw    %gs:offset
327         popw    %gs:selector
328         addw    %gs:nbytes,%esp
329         pushw   %gs:selector
330         pushw   %gs:offset
331 noargs:
333         /*
334          * Last, but not least we need to move the high word from eax to dx
335          */
337         pushl   %eax
338         popw    %dx
339         popw    %dx
341         .byte   0x66
342         lret
344 /**********************************************************************
345  *      CallTo32_16()
347  *      This function is same one as CallTo32() except that the high
348  *      word of EAX won't be moved to DX.
349  */
350         .align  4
351         .globl _CallTo32_16
352 _CallTo32_16:
353         pushl   %ebp
354         movl    %esp,%ebp
356         /*
357          * Save registers.  286 mode does not have fs or gs.
358          */
359         pushw   %ds
360         pushw   %es
362         /*
363          * Restore segment registers.
364          */
365         pushl   %eax
366         movw    $UDATASEL,%ax
367         movw    %ax,%ds
368         movw    %ax,%es
369         popl    %eax
371         /*
372          * Save old stack save variables, save stack registers, reload
373          * stack registers.
374          */
375         pushl   _IF1632_Saved16_esp
376         pushl   _IF1632_Saved16_ebp
377         pushw   _IF1632_Saved16_ss
379         movw    %ss,_IF1632_Saved16_ss
380         movl    %esp,_IF1632_Saved16_esp
381         movl    %ebp,_IF1632_Saved16_ebp
383         movw    _IF1632_Saved32_ss,%ss
384         movl    _IF1632_Saved32_esp,%esp
385         movl    _IF1632_Saved32_ebp,%ebp
387         /*
388          * Call entry point
389          */
390         pushl   %edx
391         pushw   _IF1632_Saved16_ss
392         pushw   _IF1632_Saved16_esp
393         pushl   %eax
394         call    _DLLRelay
396         popl    %edx
397         popl    %edx
398         popl    %edx
400         /*
401          * Restore registers, but do not destroy return value.
402          */
403         movw    _IF1632_Saved16_ss,%ss
404         movl    _IF1632_Saved16_esp,%esp
405         movl    _IF1632_Saved16_ebp,%ebp
407         popw    _IF1632_Saved16_ss
408         popl    _IF1632_Saved16_ebp
409         popl    _IF1632_Saved16_esp
411         popw    %es
412         popw    %ds
414         .align  2,0x90
415         leave
416         /*
417          * Now we need to ditch the parameter bytes that were left on the
418          * stack. We do this by effectively popping the number of bytes,
419          * and the return address, removing the parameters and then putting
420          * the return address back on the stack.
421          * Normally this field is filled in by the relevant function in
422          * the emulation library, since it should know how many bytes to
423          * expect.
424          */
425         popw    %gs:nbytes
426         cmpw    $0,%gs:nbytes
427         je      noargs2
428         popw    %gs:offset
429         popw    %gs:selector
430         addw    %gs:nbytes,%esp
431         pushw   %gs:selector
432         pushw   %gs:offset
433 noargs2:
434         .byte   0x66
435         lret
437 /**********************************************************************
438  *      ReturnFromRegisterFunc()
439  */
440         .globl _ReturnFromRegisterFunc
441 _ReturnFromRegisterFunc:
442         /*
443          * Restore 16-bit stack
444          */
445         movw    _IF1632_Saved16_ss,%ss
446         movl    _IF1632_Saved16_esp,%esp
447         movl    _IF1632_Saved16_ebp,%ebp
449         popw    _IF1632_Saved16_ss
450         popl    _IF1632_Saved16_ebp
451         popl    _IF1632_Saved16_esp
453         popw    %es
454         popw    %ds
456         .align  2,0x90
457         leave
458         /*
459          * This leaves us with a stack that has number of arguments,
460          * the return address, the saved registers, and the return 
461          * address again.
462          */
463         add     $6,%esp         /* argument count, return address */
464 #include "pop.h"                /* restore context                */
466         /*
467          * Return to original caller.
468          */
469         .byte   0x66
470         lret