Release 940510
[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         .data
11 jump_target:
12 return_value:
13         .long   0
14
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
25
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
36
37 nbytes:
38         .word   0
39 selector:
40         .word   0
41 offset:
42         .word   0
43
44         .text
45 \f
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
63
64         /*
65          * Save our registers
66          */
67         pushal
68         pushl   _IF1632_Saved32_esp
69         pushl   _IF1632_Saved32_ebp
70         pushw   _IF1632_Saved32_ss
71
72         /*
73          * Get target address.
74          */
75         movl    8(%ebp),%eax
76         movl    %eax,jump_target
77         lea     jump_target,%edx
78
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
85
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 */
109
110         /*
111          * Call entry point
112          */
113         .byte   0x66
114         lcall   %fs:(%edx)
115 \f
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
137
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
150 \f
151 /**********************************************************************
152  *      int CallTo16(unsigned long csip, unsigned short ds)
153  *
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
165
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
173
174         /*
175          * Switch to 16-bit stack
176          */
177         pushl   _IF1632_Saved32_esp
178         pushl   _IF1632_Saved32_ebp
179         pushw   _IF1632_Saved32_ss
180
181         movw    %ss,_IF1632_Saved32_ss
182         movl    %esp,_IF1632_Saved32_esp
183         movl    %ebp,_IF1632_Saved32_ebp
184
185         movw    _IF1632_Saved16_ss,%ss
186         movl    _IF1632_Saved16_esp,%esp
187         movl    _IF1632_Saved16_ebp,%ebp
188
189         /*
190          * Call entry point
191          */
192         movw    %ax,%ds
193         .byte   0x66
194         lcall   %fs:(%edx)
195 \f
196         /*
197          * Restore old stack and segment registers.
198          *
199          * Two choices here:
200          *      1. Trust that fs or gs hasn't changed.
201          *      2. Rely on knowledge of Linux use of segments.
202          *
203          * I'll opt for choice 2 because who knows what programs we
204          * going to run.  Linux should be fairly stable in terms of
205          * GDT usage.
206          */
207         pushl   %eax
208         movw    $UDATASEL,%ax
209         movw    %ax,%ds
210         movw    %ax,%es
211         movw    %ax,%fs
212         movw    %ax,%gs
213         popl    %eax
214
215         movw    %ss,_IF1632_Saved16_ss
216         movl    %esp,_IF1632_Saved16_esp
217         movl    %ebp,_IF1632_Saved16_ebp
218
219         movw    _IF1632_Saved32_ss,%ss
220         movl    _IF1632_Saved32_esp,%esp
221         movl    _IF1632_Saved32_ebp,%ebp
222
223         popw    _IF1632_Saved32_ss
224         popl    _IF1632_Saved32_ebp
225         popl    _IF1632_Saved32_esp
226
227         movl    %eax,return_value
228         movw    return_value+2,%dx
229         .align  2,0x90
230         leave
231         ret
232 \f
233 /**********************************************************************
234  *      CallTo32()
235  *
236  *      This function is called as a relay point to the built function
237  *      handler.  KERNEL, USER and GDI calls are dealt with by this
238  *      handler.  Calls to these DLLs will be mapped to a call handler
239  *      which will set EAX to a number indicating which DLL and which
240  *      function within that DLL.
241  *
242  *      This function will pass to the function handler two arguments.
243  *      The first argument will be the contents of EAX, the second
244  *      argument will be a segment:offset pair that points to the
245  *      16-bit stack.
246  */
247         .align  4
248         .globl _CallTo32
249 _CallTo32:
250         pushl   %ebp
251         movl    %esp,%ebp
252
253         /*
254          * Save registers.  286 mode does not have fs or gs.
255          */
256         pushw   %ds
257         pushw   %es
258
259         /*
260          * Restore segment registers.
261          */
262         pushl   %eax
263         movw    $UDATASEL,%ax
264         movw    %ax,%ds
265         movw    %ax,%es
266         popl    %eax
267
268         /*
269          * Save old stack save variables, save stack registers, reload
270          * stack registers.
271          */
272         pushl   _IF1632_Saved16_esp
273         pushl   _IF1632_Saved16_ebp
274         pushw   _IF1632_Saved16_ss
275
276         movw    %ss,_IF1632_Saved16_ss
277         movl    %esp,_IF1632_Saved16_esp
278         movl    %ebp,_IF1632_Saved16_ebp
279
280         movw    _IF1632_Saved32_ss,%ss
281         movl    _IF1632_Saved32_esp,%esp
282         movl    _IF1632_Saved32_ebp,%ebp
283
284         /*
285          * Call entry point
286          */
287         pushw   _IF1632_Saved16_ss
288         pushw   _IF1632_Saved16_esp
289         pushl   %eax
290         call    _DLLRelay
291 \f
292         /*
293          * Restore registers, but do not destroy return value.
294          */
295         movw    _IF1632_Saved16_ss,%ss
296         movl    _IF1632_Saved16_esp,%esp
297         movl    _IF1632_Saved16_ebp,%ebp
298
299         popw    _IF1632_Saved16_ss
300         popl    _IF1632_Saved16_ebp
301         popl    _IF1632_Saved16_esp
302
303         popw    %es
304         popw    %ds
305
306         .align  2,0x90
307         leave
308         /*
309          * Now we need to ditch the parameter bytes that were left on the
310          * stack. We do this by effectively popping the number of bytes,
311          * and the return address, removing the parameters and then putting
312          * the return address back on the stack.
313          * Normally this field is filled in by the relevant function in
314          * the emulation library, since it should know how many bytes to
315          * expect.
316          */
317         popw    %gs:nbytes
318         cmpw    $0,%gs:nbytes
319         je      noargs
320         popw    %gs:offset
321         popw    %gs:selector
322         addw    %gs:nbytes,%esp
323         pushw   %gs:selector
324         pushw   %gs:offset
325 noargs:
326
327         /*
328          * Last, but not least we need to move the high word from eax to dx
329          */
330         pushl   %eax
331         popw    %dx
332         popw    %dx
333
334         .byte   0x66
335         lret
336 \f
337 /**********************************************************************
338  *      ReturnFromRegisterFunc()
339  */
340         .globl _ReturnFromRegisterFunc
341 _ReturnFromRegisterFunc:
342         /*
343          * Restore 16-bit stack
344          */
345         movw    _IF1632_Saved16_ss,%ss
346         movl    _IF1632_Saved16_esp,%esp
347         movl    _IF1632_Saved16_ebp,%ebp
348
349         popw    _IF1632_Saved16_ss
350         popl    _IF1632_Saved16_ebp
351         popl    _IF1632_Saved16_esp
352
353         popw    %es
354         popw    %ds
355
356         .align  2,0x90
357         leave
358         /*
359          * This leaves us with a stack that has number of arguments,
360          * the return address, the saved registers, and the return 
361          * address again.
362          */
363         add     $6,%esp         /* argument count, return address */
364 #include "pop.h"                /* restore context                */
365
366         /*
367          * Return to original caller.
368          */
369         .byte   0x66
370         lret
371