Release 941107
[wine/multimedia.git] / if1632 / call.S
blob2d5ed8db62acce496f03949f575641329578f1c5
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
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
31 /**********************************************************************
32  *      Places to keep info about the current 16-bit stack frame.
33  */
34         .globl A(IF1632_Saved16_esp),A(IF1632_Saved16_ebp),A(IF1632_Saved16_ss)
35 A(IF1632_Saved16_esp:)
36         .long   0
37 A(IF1632_Saved16_ebp:)
38         .long   0
39 A(IF1632_Saved16_ss:)
40         .word   0
42 nbytes:
43         .word   0
44 selector:
45         .word   0
46 offset:
47         .word   0
49         .text
51 /**********************************************************************
52  *      int CallToInit16(unsigned long csip, unsigned long sssp,
53  *                   unsigned short ds)
54  *
55  *      Stack:          0       ebp
56  *                      4       eip
57  *                      8       target ip
58  *                      10      target cs
59  *                      12      target sp
60  *                      14      target ss
61  *                      16      target ds
62  */
63         .align  4
64         .globl A(CallToInit16)
65 A(CallToInit16:)
66         pushl   %ebp
67         movl    %esp,%ebp
69         /*
70          * Save our registers
71          */
72         pushal
73         pushl   A(IF1632_Saved32_esp)
74         pushl   A(IF1632_Saved32_ebp)
75         pushw   A(IF1632_Saved32_ss)
77         /*
78          * Get target address.
79          */
80         movl    8(%ebp),%eax
81         movl    %eax,jump_target
82         lea     jump_target,%edx
84         /*
85          * Put stack registers where we can get them after stack switch.
86          */
87         movw    %ss,A(IF1632_Saved32_ss)
88         movl    %esp,A(IF1632_Saved32_esp)
89         movl    %ebp,A(IF1632_Saved32_ebp)
91         /*
92          * Load initial registers
93          */
94         movw    A(WIN_StackSize),%bx
95         movw    A(WIN_HeapSize),%cx
96         movl    $0,%esi
97         xorl    %eax,%eax
98         movw    A(PSPSelector),%ax
99         movw    %ax,%es
100         movw    16(%ebp),%ax
101         movw    %ax,%ds
102         movl    %eax,%edi
103         xorl    %eax,%eax
104         movw    12(%ebp),%ax
105         movl    %eax,%esp
106         movw    14(%ebp),%ax
107         movw    %ax,%ss
108         movl    %esp,%eax
109         movl    %eax,%ebp
110         movw    $UDATASEL,%ax
111         movw    %ax,%fs
112         movw    %ax,%gs
113         movw    %ds,%ax
115         /*
116          * Call entry point
117          */
118         .byte   0x66
119         lcall   %fs:(%edx)
121         /*
122          * Restore old stack and segment registers.
123          *
124          * Two choices here:
125          *      1. Trust that fs or gs hasn't changed.
126          *      2. Rely on knowledge of Linux use of segments.
127          *
128          * I'll opt for choice 2 because who knows what programs we
129          * going to run.  Linux should be fairly stable in terms of
130          * GDT usage.
131          */
132         pushl   %eax
133         movw    $UDATASEL,%ax
134         movw    %ax,%ds
135         movw    %ax,%es
136         movw    %ax,%fs
137         movw    %ax,%gs
138         popl    %eax
139         movw    A(IF1632_Saved32_ss),%ss
140         movl    A(IF1632_Saved32_esp),%esp
141         movl    A(IF1632_Saved32_ebp),%ebp
143         /*
144          * Restore registers, but do not destroy return value.
145          */
146         popw    A(IF1632_Saved32_ss)
147         popl    A(IF1632_Saved32_ebp)
148         popl    A(IF1632_Saved32_esp)
149         movl    %eax,return_value
150         popal
151         movl    return_value,%eax
152         .align  2,0x90
153         leave
154         ret
156 /**********************************************************************
157  *      int CallTo16  (unsigned long csip, unsigned short ds)
158  *      int CallTo16cx(unsigned long csip, unsigned long dscx);
160  *      Stack:          0       ebp
161  *                      4       eip
162  *                      8       target ip
163  *                      10      target cs
164  *                      12      target ds
165  *                      14      target cx  (only CallTo16cx)
166  */
167         .align  4
168         .globl A(CallTo16), A(CallTo16cx)
169 A(CallTo16:)
170 A(CallTo16cx:)
171         pushl   %ebp
172         movl    %esp,%ebp
174         /*
175          * Get target address and new ds
176          */
177         movl    8(%ebp),%eax
178         movl    %eax,jump_target
179         lea     jump_target,%edx
180         movw    12(%ebp),%ax
181         movw    14(%ebp),%cx
183         /*
184          * Switch to 16-bit stack
185          */
186         pushl   A(IF1632_Saved32_esp)
187         pushl   A(IF1632_Saved32_ebp)
188         pushw   A(IF1632_Saved32_ss)
190         movw    %ss,A(IF1632_Saved32_ss)
191         movl    %esp,A(IF1632_Saved32_esp)
192         movl    %ebp,A(IF1632_Saved32_ebp)
194         movw    A(IF1632_Saved16_ss),%ss
195         movl    A(IF1632_Saved16_esp),%esp
196         movl    A(IF1632_Saved16_ebp),%ebp
198         /*
199          * Call entry point
200          */
201         movw    %ax,%ds
202         movw    %ax,%di
203         .byte   0x66
204         lcall   %fs:(%edx)
206         /*
207          * Restore old stack and segment registers.
208          *
209          * Two choices here:
210          *      1. Trust that fs or gs hasn't changed.
211          *      2. Rely on knowledge of Linux use of segments.
212          *
213          * I'll opt for choice 2 because who knows what programs we
214          * going to run.  Linux should be fairly stable in terms of
215          * GDT usage.
216          */
217         pushl   %eax
218         movw    $UDATASEL,%ax
219         movw    %ax,%ds
220         movw    %ax,%es
221         movw    %ax,%fs
222         movw    %ax,%gs
223         popl    %eax
225         movw    %ss,A(IF1632_Saved16_ss)
226         movl    %esp,A(IF1632_Saved16_esp)
227         movl    %ebp,A(IF1632_Saved16_ebp)
229         movw    A(IF1632_Saved32_ss),%ss
230         movl    A(IF1632_Saved32_esp),%esp
231         movl    A(IF1632_Saved32_ebp),%ebp
233         popw    A(IF1632_Saved32_ss)
234         popl    A(IF1632_Saved32_ebp)
235         popl    A(IF1632_Saved32_esp)
237         movl    %eax,return_value
238         movw    return_value+2,%dx
239         .align  2,0x90
240         leave
241         ret
243 /**********************************************************************
244  *      CallTo32()
246  *      This function is called as a relay point to the built function
247  *      handler.  KERNEL, USER and GDI calls are dealt with by this
248  *      handler.  Calls to these DLLs will be mapped to a call handler
249  *      which will set EAX to a number indicating which DLL and which
250  *      function within that DLL.
252  *      This function will pass to the function handler two arguments.
253  *      The first argument will be the contents of EAX, the second
254  *      argument will be a segment:offset pair that points to the
255  *      16-bit stack.
256  */
257         .align  4
258         .globl A(CallTo32)
259 A(CallTo32:)
260         pushl   %ebp
261         movl    %esp,%ebp
263         /*
264          * Save registers.  286 mode does not have fs or gs.
265          */
266         pushw   %ds
267         pushw   %es
269         /*
270          * Restore segment registers.
271          */
272         pushl   %eax
273         movw    $UDATASEL,%ax
274         movw    %ax,%ds
275         movw    %ax,%es
276         popl    %eax
278         /*
279          * Save old stack save variables, save stack registers, reload
280          * stack registers.
281          */
282         pushl   A(IF1632_Saved16_esp)
283         pushl   A(IF1632_Saved16_ebp)
284         pushw   A(IF1632_Saved16_ss)
286         movw    %ss,A(IF1632_Saved16_ss)
287         movl    %esp,A(IF1632_Saved16_esp)
288         movl    %ebp,A(IF1632_Saved16_ebp)
290         movw    A(IF1632_Saved32_ss),%ss
291         movl    A(IF1632_Saved32_esp),%esp
292         movl    A(IF1632_Saved32_ebp),%ebp
294         /*
295          * Call entry point
296          */
297         pushl   %edx
298         pushw   A(IF1632_Saved16_ss)
299         pushw   A(IF1632_Saved16_esp)
300         pushl   %eax
301         call    A(DLLRelay)
303         popl    %edx
304         popl    %edx
305         popl    %edx
307         /*
308          * Restore registers, but do not destroy return value.
309          */
310         movw    A(IF1632_Saved16_ss),%ss
311         movl    A(IF1632_Saved16_esp),%esp
312         movl    A(IF1632_Saved16_ebp),%ebp
314         popw    A(IF1632_Saved16_ss)
315         popl    A(IF1632_Saved16_ebp)
316         popl    A(IF1632_Saved16_esp)
318         popw    %es
319         popw    %ds
321         .align  2,0x90
322         leave
323         /*
324          * Now we need to ditch the parameter bytes that were left on the
325          * stack. We do this by effectively popping the number of bytes,
326          * and the return address, removing the parameters and then putting
327          * the return address back on the stack.
328          * Normally this field is filled in by the relevant function in
329          * the emulation library, since it should know how many bytes to
330          * expect.
331          */
332         popw    %gs:nbytes
333         cmpw    $0,%gs:nbytes
334         je      noargs
335         popw    %gs:offset
336         popw    %gs:selector
337         addw    %gs:nbytes,%esp
338         pushw   %gs:selector
339         pushw   %gs:offset
340 noargs:
342         /*
343          * Last, but not least we need to move the high word from eax to dx
344          */
346         pushl   %eax
347         popw    %dx
348         popw    %dx
350         .byte   0x66
351         lret
353 /**********************************************************************
354  *      CallTo32_16()
356  *      This function is same one as CallTo32() except that the high
357  *      word of EAX won't be moved to DX.
358  */
359         .align  4
360         .globl A(CallTo32_16)
361 A(CallTo32_16:)
362         pushl   %ebp
363         movl    %esp,%ebp
365         /*
366          * Save registers.  286 mode does not have fs or gs.
367          */
368         pushw   %ds
369         pushw   %es
371         /*
372          * Restore segment registers.
373          */
374         pushl   %eax
375         movw    $UDATASEL,%ax
376         movw    %ax,%ds
377         movw    %ax,%es
378         popl    %eax
380         /*
381          * Save old stack save variables, save stack registers, reload
382          * stack registers.
383          */
384         pushl   A(IF1632_Saved16_esp)
385         pushl   A(IF1632_Saved16_ebp)
386         pushw   A(IF1632_Saved16_ss)
388         movw    %ss,A(IF1632_Saved16_ss)
389         movl    %esp,A(IF1632_Saved16_esp)
390         movl    %ebp,A(IF1632_Saved16_ebp)
392         movw    A(IF1632_Saved32_ss),%ss
393         movl    A(IF1632_Saved32_esp),%esp
394         movl    A(IF1632_Saved32_ebp),%ebp
396         /*
397          * Call entry point
398          */
399         pushl   %edx
400         pushw   A(IF1632_Saved16_ss)
401         pushw   A(IF1632_Saved16_esp)
402         pushl   %eax
403         call    A(DLLRelay)
405         popl    %edx
406         popl    %edx
407         popl    %edx
409         /*
410          * Restore registers, but do not destroy return value.
411          */
412         movw    A(IF1632_Saved16_ss),%ss
413         movl    A(IF1632_Saved16_esp),%esp
414         movl    A(IF1632_Saved16_ebp),%ebp
416         popw    A(IF1632_Saved16_ss)
417         popl    A(IF1632_Saved16_ebp)
418         popl    A(IF1632_Saved16_esp)
420         popw    %es
421         popw    %ds
423         .align  2,0x90
424         leave
425         /*
426          * Now we need to ditch the parameter bytes that were left on the
427          * stack. We do this by effectively popping the number of bytes,
428          * and the return address, removing the parameters and then putting
429          * the return address back on the stack.
430          * Normally this field is filled in by the relevant function in
431          * the emulation library, since it should know how many bytes to
432          * expect.
433          */
434         popw    %gs:nbytes
435         cmpw    $0,%gs:nbytes
436         je      noargs2
437         popw    %gs:offset
438         popw    %gs:selector
439         addw    %gs:nbytes,%esp
440         pushw   %gs:selector
441         pushw   %gs:offset
442 noargs2:
443         .byte   0x66
444         lret
446 /**********************************************************************
447  *      ReturnFromRegisterFunc()
448  */
449         .globl A(ReturnFromRegisterFunc)
450 A(ReturnFromRegisterFunc:)
451         /*
452          * Restore 16-bit stack
453          */
454         movw    A(IF1632_Saved16_ss),%ss
455         movl    A(IF1632_Saved16_esp),%esp
456         movl    A(IF1632_Saved16_ebp),%ebp
458         popw    A(IF1632_Saved16_ss)
459         popl    A(IF1632_Saved16_ebp)
460         popl    A(IF1632_Saved16_esp)
462         popw    %es
463         popw    %ds
465         .align  2,0x90
466         leave
467         /*
468          * This leaves us with a stack that has number of arguments,
469          * the return address, the saved registers, and the return 
470          * address again.
471          */
472         add     $6,%esp         /* argument count, return address */
473 #include "pop.h"                /* restore context                */
475         /*
476          * Return to original caller.
477          */
478         .byte   0x66
479         lret