Release 0.3.0
[wine/multimedia.git] / if1632 / call.S
blobc5e9e05da49b5e1ea702d029c3a386e6a3f1552e
1 /*
2  * Copyright  Robert J. Amstadt, 1993
3  */
4         .data
5 jump_target:
6 return_value:
7         .long   0
9 /**********************************************************************
10  *      Places to keep info about the current 32-bit stack frame.
11  */
12 saved_esp:
13         .long   0
14 saved_ebp:
15         .long   0
16 saved_ss:
17         .word   0
19 /**********************************************************************
20  *      Places to keep info about the current 16-bit stack frame.
21  */
22         .globl  _IF1632_Saved16_esp,_IF1632_Saved16_ebp,_IF1632_Saved16_ss
23 _IF1632_Saved16_esp:
24         .long   0
25 _IF1632_Saved16_ebp:
26         .long   0
27 _IF1632_Saved16_ss:
28         .word   0
30 nbytes:
31         .word   0
32 selector:
33         .word   0
34 offset:
35         .word   0
37         .text
39 /**********************************************************************
40  *      int CallToInit16(unsigned long csip, unsigned long sssp,
41  *                   unsigned short ds)
42  *
43  *      Stack:          0       ebp
44  *                      4       eip
45  *                      8       target ip
46  *                      10      target cs
47  *                      12      target sp
48  *                      14      target ss
49  *                      16      target ds
50  */
51         .align  4
52         .globl _CallToInit16
53 _CallToInit16:
54         pushl   %ebp
55         movl    %esp,%ebp
57         /*
58          * Save our registers
59          */
60         pushal
61         pushl   saved_esp
62         pushl   saved_ebp
63         pushw   saved_ss
65         /*
66          * Get target address.
67          */
68         movl    8(%ebp),%eax
69         movl    %eax,jump_target
70         lea     jump_target,%edx
72         /*
73          * Put stack registers where we can get them after stack switch.
74          */
75         movw    %ss,saved_ss
76         movl    %esp,saved_esp
77         movl    %ebp,saved_ebp
79         /*
80          * Load initial registers
81          */
82         movw    _WIN_StackSize,%bx
83         movw    _WIN_HeapSize,%cx
84         movl    $0,%esi
85         xorl    %eax,%eax
86         movw    _PSPSelector,%ax
87         movw    %ax,%es
88         movw    16(%ebp),%ax
89         movw    %ax,%ds
90         movl    %eax,%edi
91         xorl    %eax,%eax
92         movw    12(%ebp),%ax
93         movl    %eax,%esp
94         movw    14(%ebp),%ax
95         movw    %ax,%ss
96         movl    %esp,%eax
97         movl    %eax,%ebp
99         /*
100          * Call entry point
101          */
102         .byte   0x66
103         lcall   %fs:(%edx)
105         /*
106          * Restore old stack and segment registers.
107          *
108          * Two choices here:
109          *      1. Trust that fs or gs hasn't changed.
110          *      2. Rely on knowledge of Linux use of segments.
111          *
112          * I'll opt for choice 2 because who knows what programs we
113          * going to run.  Linux should be fairly stable in terms of
114          * GDT usage.
115          */
116         pushl   %eax
117         movw    $0x2b,%ax
118         movw    %ax,%ds
119         movw    %ax,%es
120         movw    %ax,%fs
121         movw    %ax,%gs
122         popl    %eax
123         movw    saved_ss,%ss
124         movl    saved_esp,%esp
125         movl    saved_ebp,%ebp
127         /*
128          * Restore registers, but do not destroy return value.
129          */
130         popw    saved_ss
131         popl    saved_ebp
132         popl    saved_esp
133         movl    %eax,return_value
134         popal
135         movl    return_value,%eax
136         .align  2,0x90
137         leave
138         ret
140 /**********************************************************************
141  *      int CallTo16(unsigned long csip, unsigned short ds)
143  *      Stack:          0       ebp
144  *                      4       eip
145  *                      8       target ip
146  *                      10      target cs
147  *                      12      target ds
148  */
149         .align  4
150         .globl _CallTo16
151 _CallTo16:
152         pushl   %ebp
153         movl    %esp,%ebp
155         /*
156          * Get target address and new ds
157          */
158         movl    8(%ebp),%eax
159         movl    %eax,jump_target
160         lea     jump_target,%edx
161         movw    12(%ebp),%ax
163         /*
164          * Switch to 16-bit stack
165          */
166         pushl   saved_esp
167         pushl   saved_ebp
168         pushw   saved_ss
170         movw    %ss,saved_ss
171         movl    %esp,saved_esp
172         movl    %ebp,saved_ebp
174         movw    _IF1632_Saved16_ss,%ss
175         movl    _IF1632_Saved16_esp,%esp
176         movl    _IF1632_Saved16_ebp,%ebp
178         /*
179          * Call entry point
180          */
181         movw    %ax,%ds
182         .byte   0x66
183         lcall   %fs:(%edx)
185         /*
186          * Restore old stack and segment registers.
187          *
188          * Two choices here:
189          *      1. Trust that fs or gs hasn't changed.
190          *      2. Rely on knowledge of Linux use of segments.
191          *
192          * I'll opt for choice 2 because who knows what programs we
193          * going to run.  Linux should be fairly stable in terms of
194          * GDT usage.
195          */
196         pushl   %eax
197         movw    $0x2b,%ax
198         movw    %ax,%ds
199         movw    %ax,%es
200         movw    %ax,%fs
201         movw    %ax,%gs
202         popl    %eax
204         movw    %ss,_IF1632_Saved16_ss
205         movl    %esp,_IF1632_Saved16_esp
206         movl    %ebp,_IF1632_Saved16_ebp
208         movw    saved_ss,%ss
209         movl    saved_esp,%esp
210         movl    saved_ebp,%ebp
212         popw    saved_ss
213         popl    saved_ebp
214         popl    saved_esp
216         movl    %eax,return_value
217         movw    return_value+2,%dx
218         .align  2,0x90
219         leave
220         ret
222 /**********************************************************************
223  *      CallTo32()
225  *      This function is called as a relay point to the built function
226  *      handler.  KERNEL, USER and GDI calls are dealt with by this
227  *      handler.  Calls to these DLLs will be mapped to a call handler
228  *      which will set EAX to a number indicating which DLL and which
229  *      function within that DLL.
231  *      This function will pass to the function handler two arguments.
232  *      The first argument will be the contents of EAX, the second
233  *      argument will be a segment:offset pair that points to the
234  *      16-bit stack.
235  */
236         .align  4
237         .globl _CallTo32
238 _CallTo32:
239         pushl   %ebp
240         movl    %esp,%ebp
242         /*
243          * Save registers.  286 mode does not have fs or gs.
244          */
245         pushw   %ds
246         pushw   %es
248         /*
249          * Restore segment registers.
250          */
251         pushl   %eax
252         movw    $0x2b,%ax
253         movw    %ax,%ds
254         movw    %ax,%es
255         popl    %eax
257         /*
258          * Save old stack save variables, save stack registers, reload
259          * stack registers.
260          */
261         pushl   _IF1632_Saved16_esp
262         pushl   _IF1632_Saved16_ebp
263         pushw   _IF1632_Saved16_ss
265         movw    %ss,_IF1632_Saved16_ss
266         movl    %esp,_IF1632_Saved16_esp
267         movl    %ebp,_IF1632_Saved16_ebp
269         movw    saved_ss,%ss
270         movl    saved_esp,%esp
271         movl    saved_ebp,%ebp
273         /*
274          * Call entry point
275          */
276         pushw   _IF1632_Saved16_ss
277         pushw   _IF1632_Saved16_esp
278         pushl   %eax
279         call    _DLLRelay
281         /*
282          * Restore registers, but do not destroy return value.
283          */
284         movw    _IF1632_Saved16_ss,%ss
285         movl    _IF1632_Saved16_esp,%esp
286         movl    _IF1632_Saved16_ebp,%ebp
288         popw    _IF1632_Saved16_ss
289         popl    _IF1632_Saved16_ebp
290         popl    _IF1632_Saved16_esp
292         popw    %es
293         popw    %ds
295         .align  2,0x90
296         leave
297         /*
298          * Now we need to ditch the parameter bytes that were left on the
299          * stack. We do this by effectively popping the number of bytes,
300          * and the return address, removing the parameters and then putting
301          * the return address back on the stack.
302          * Normally this field is filled in by the relevant function in
303          * the emulation library, since it should know how many bytes to
304          * expect.
305          */
306         popw    %gs:nbytes
307         cmpw    $0,%gs:nbytes
308         je      noargs
309         popw    %gs:offset
310         popw    %gs:selector
311         addw    %gs:nbytes,%esp
312         pushw   %gs:selector
313         pushw   %gs:offset
314 noargs:
316         /*
317          * Last, but not least we need to move the high word from eax to dx
318          */
319         pushl   %eax
320         popw    %dx
321         popw    %dx
323         .byte   0x66
324         lret
326 /**********************************************************************
327  *      ReturnFromRegisterFunc()
328  */
329         .globl _ReturnFromRegisterFunc
330 _ReturnFromRegisterFunc:
331         /*
332          * Restore 16-bit stack
333          */
334         movw    _IF1632_Saved16_ss,%ss
335         movl    _IF1632_Saved16_esp,%esp
336         movl    _IF1632_Saved16_ebp,%ebp
338         popw    _IF1632_Saved16_ss
339         popl    _IF1632_Saved16_ebp
340         popl    _IF1632_Saved16_esp
342         popw    %es
343         popw    %ds
345         .align  2,0x90
346         leave
347         /*
348          * This leaves us with a stack that has number of arguments,
349          * the return address, the saved registers, and the return 
350          * address again.
351          */
352         popw    %ax     /* Throw away the number of arguments */
353         popl    %eax    /* Throw away first copy of return address */
354         popw    %es
355         popw    %ds
356         popw    %di
357         popw    %si
358         popw    %bp
359         popw    %ax     /* Throw away pushed stack pointer */
360         popw    %bx
361         popw    %dx
362         popw    %cx
363         popw    %ax
365         /*
366          * Return to original caller.
367          */
368         .byte   0x66
369         lret