Release 950122
[wine/multimedia.git] / if1632 / call.S
blob326c874396a02f7a822fba5ed16f5641ebc73a0e
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
30 #ifdef __ELF__
31 A(IF1632_ELF_KLUDGE:)
32         .long   0
33         .word   0x0f
34 #endif
36 /**********************************************************************
37  *      Places to keep info about the current 16-bit stack frame.
38  */
39         .globl A(IF1632_Saved16_esp),A(IF1632_Saved16_ebp),A(IF1632_Saved16_ss)
40 A(IF1632_Saved16_esp:)
41         .long   0
42 A(IF1632_Saved16_ebp:)
43         .long   0
44 A(IF1632_Saved16_ss:)
45         .word   0
47 nbytes:
48         .word   0
49 selector:
50         .word   0
51 offset:
52         .word   0
54         .text
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
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)
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
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)
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
130         /*
131          * Call entry point
132          */
133         .byte   0x66
134         lcall   %fs:(%edx)
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
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)
173 #endif
174         popal
175         movl    return_value,%eax
176         .align  2,0x90
177         leave
178         ret
180 /**********************************************************************
181  *      int CallTo16  (unsigned long csip, unsigned short ds)
182  *      int CallTo16cx(unsigned long csip, unsigned long dscx);
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
206         /*
207          * Get target address and new ds
208          */
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)
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
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)
234         movw    %ss,A(IF1632_Saved32_ss)
235         movl    %esp,A(IF1632_Saved32_esp)
236         movl    %ebp,A(IF1632_Saved32_ebp)
238         movw    A(IF1632_Saved16_ss),%ss
239         movl    A(IF1632_Saved16_esp),%esp
240         movl    A(IF1632_Saved16_ebp),%ebp
242         /*
243          * Call entry point
244          */
245         movw    %ax,%ds
246         movw    %ax,%di
247         .byte   0x66
248         lcall   %fs:(%edx)
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
269         movw    %ss,A(IF1632_Saved16_ss)
270         movl    %esp,A(IF1632_Saved16_esp)
271         movl    %ebp,A(IF1632_Saved16_ebp)
273         movw    A(IF1632_Saved32_ss),%ss
274         movl    A(IF1632_Saved32_esp),%esp
275         movl    A(IF1632_Saved32_ebp),%ebp
277         popw    A(IF1632_Saved32_ss)
278         popl    A(IF1632_Saved32_ebp)
279         popl    A(IF1632_Saved32_esp)
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)
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
299 /**********************************************************************
300  *      CallTo32()
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.
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         pushl   %ebp
317         movl    %esp,%ebp
319         /*
320          * Save registers.  286 mode does not have fs or gs.
321          */
322         pushw   %ds
323         pushw   %es
325         /*
326          * Restore segment registers.
327          */
328         pushl   %eax
329         movw    $UDATASEL,%ax
330         movw    %ax,%ds
331         movw    %ax,%es
332         popl    %eax
334         /*
335          * Save old stack save variables, save stack registers, reload
336          * stack registers.
337          */
338         pushl   A(IF1632_Saved16_esp)
339         pushl   A(IF1632_Saved16_ebp)
340         pushw   A(IF1632_Saved16_ss)
342         movw    %ss,A(IF1632_Saved16_ss)
343         movl    %esp,A(IF1632_Saved16_esp)
344         movl    %ebp,A(IF1632_Saved16_ebp)
346         movw    A(IF1632_Saved32_ss),%ss
347         movl    A(IF1632_Saved32_esp),%esp
348         movl    A(IF1632_Saved32_ebp),%ebp
350         /*
351          * Call entry point
352          */
353         pushl   %edx
354         pushw   A(IF1632_Saved16_ss)
355         pushw   A(IF1632_Saved16_esp)
356         pushl   %eax
357         call    A(DLLRelay)
359         popl    %edx
360         popl    %edx
361         popl    %edx
363         /*
364          * Restore registers, but do not destroy return value.
365          */
366         movw    A(IF1632_Saved16_ss),%ss
367         movl    A(IF1632_Saved16_esp),%esp
368         movl    A(IF1632_Saved16_ebp),%ebp
370         popw    A(IF1632_Saved16_ss)
371         popl    A(IF1632_Saved16_ebp)
372         popl    A(IF1632_Saved16_esp)
374         popw    %es
375         popw    %ds
377         .align  2,0x90
378         leave
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:
398         /*
399          * Last, but not least we need to move the high word from eax to dx
400          */
402         pushl   %eax
403         popw    %dx
404         popw    %dx
406         .byte   0x66
407         lret
409 /**********************************************************************
410  *      CallTo32_16()
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         pushl   %ebp
419         movl    %esp,%ebp
421         /*
422          * Save registers.  286 mode does not have fs or gs.
423          */
424         pushw   %ds
425         pushw   %es
427         /*
428          * Restore segment registers.
429          */
430         pushl   %eax
431         movw    $UDATASEL,%ax
432         movw    %ax,%ds
433         movw    %ax,%es
434         popl    %eax
436         /*
437          * Save old stack save variables, save stack registers, reload
438          * stack registers.
439          */
440         pushl   A(IF1632_Saved16_esp)
441         pushl   A(IF1632_Saved16_ebp)
442         pushw   A(IF1632_Saved16_ss)
444         movw    %ss,A(IF1632_Saved16_ss)
445         movl    %esp,A(IF1632_Saved16_esp)
446         movl    %ebp,A(IF1632_Saved16_ebp)
448         movw    A(IF1632_Saved32_ss),%ss
449         movl    A(IF1632_Saved32_esp),%esp
450         movl    A(IF1632_Saved32_ebp),%ebp
452         /*
453          * Call entry point
454          */
455         pushl   %edx
456         pushw   A(IF1632_Saved16_ss)
457         pushw   A(IF1632_Saved16_esp)
458         pushl   %eax
459         call    A(DLLRelay)
461         popl    %edx
462         popl    %edx
463         popl    %edx
465         /*
466          * Restore registers, but do not destroy return value.
467          */
468         movw    A(IF1632_Saved16_ss),%ss
469         movl    A(IF1632_Saved16_esp),%esp
470         movl    A(IF1632_Saved16_ebp),%ebp
472         popw    A(IF1632_Saved16_ss)
473         popl    A(IF1632_Saved16_ebp)
474         popl    A(IF1632_Saved16_esp)
476         popw    %es
477         popw    %ds
479         .align  2,0x90
480         leave
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
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         movl    A(IF1632_Saved16_esp),%esp
512         movl    A(IF1632_Saved16_ebp),%ebp
514         popw    A(IF1632_Saved16_ss)
515         popl    A(IF1632_Saved16_ebp)
516         popl    A(IF1632_Saved16_esp)
518         popw    %es
519         popw    %ds
521         .align  2,0x90
522         leave
523         /*
524          * This leaves us with a stack that has number of arguments,
525          * the return address, the saved registers, and the return 
526          * address again.
527          */
528         add     $6,%esp         /* argument count, return address */
529 #include "pop.h"                /* restore context                */
531         /*
532          * Return to original caller.
533          */
534         .byte   0x66
535         lret