source: vendor/emx/current/src/os2/emxdll.asm

Last change on this file was 18, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 20.8 KB
Line 
1;
2; EMXDLL.ASM
3;
4; Copyright (c) 1992-1996 by Eberhard Mattes
5;
6; This file is part of emx.
7;
8; emx is free software; you can redistribute it and/or modify it
9; under the terms of the GNU General Public License as published by
10; the Free Software Foundation; either version 2, or (at your option)
11; any later version.
12;
13; emx is distributed in the hope that it will be useful,
14; but WITHOUT ANY WARRANTY; without even the implied warranty of
15; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16; GNU General Public License for more details.
17;
18; You should have received a copy of the GNU General Public License
19; along with emx; see the file COPYING. If not, write to
20; the Free Software Foundation, 59 Temple Place - Suite 330,
21; Boston, MA 02111-1307, USA.
22;
23; As special exception, emx.dll can be distributed without source code
24; unless it has been changed. If you modify emx.dll, this exception
25; no longer applies and you must remove this paragraph from all source
26; files for emx.dll.
27;
28
29 .386
30
31 INCLUDE EMXDLL.INC
32
33;
34; IBM TCP/IP's socket handles are < 2048. See also emxdll.h.
35;
36MAX_SOCKETS = 2048
37
38; ----------------------------------------------------------------------------
39; Structures
40; ----------------------------------------------------------------------------
41
42;
43; emx_syscall puts all the registers of the client process into the stack
44; using PUSHAD. This structure matches the layout of the registers in
45; the stack.
46;
47SYSCALL_FRAME STRUCT
48SC_EDI DWORD ?
49SC_ESI DWORD ?
50SC_EBP DWORD ?
51SC_ESP DWORD ?
52SC_EBX DWORD ?
53SC_EDX DWORD ?
54SC_ECX DWORD ?
55SC_EAX DWORD ?
56SC_EFLAGS DWORD ?
57SC_EIP DWORD ?
58SYSCALL_FRAME ENDS
59
60;
61; Thread data block. Fields at the end of the structure are omitted.
62; In consequence, the size of the structure is wrong and must not be
63; used.
64;
65THREAD_DATA STRUCT
66LAST_SYS_ERRNO DWORD ? ; Error code for last syscall
67PREV_SYS_ERRNO DWORD ? ; Previous value of the above
68; ...and other fields, which are omitted here
69THREAD_DATA ENDS
70
71; ----------------------------------------------------------------------------
72; Data
73; ----------------------------------------------------------------------------
74
75BSS32 SEGMENT
76
77;
78; The following variables are imported from other modules
79;
80 EXTRN stack_end:DWORD
81 EXTRN layout:DWORD
82 EXTRN threads:DWORD
83 EXTRN env_count:DWORD
84 EXTRN arg_size:DWORD
85 EXTRN arg_count:DWORD
86 EXTRN fork_flag:BYTE
87 EXTRN fork_stack_page:DWORD
88 EXTRN fork_ebp:DWORD
89 EXTRN exc_reg_ptr:DWORD
90 EXTRN errout_handle:DWORD
91
92;
93; Private data of this module
94;
95RET_ADDR DWORD ? ; Return address
96
97BSS32 ENDS
98
99; ----------------------------------------------------------------------------
100; Solo data
101; ----------------------------------------------------------------------------
102
103COMMON32 SEGMENT
104pipe_number DWORD ?
105queue_number DWORD ?
106sock_proc_count DWORD MAX_SOCKETS DUP (?)
107COMMON32 ENDS
108
109
110; ----------------------------------------------------------------------------
111; The code segment
112; ----------------------------------------------------------------------------
113
114TEXT32 SEGMENT
115
116 ASSUME DS:FLAT, ES:FLAT
117
118;
119; emx.dll exports the following functions of this module:
120;
121 PUBLIC emx_init
122 PUBLIC emx_syscall
123
124;
125; The following functions are exported to other modules
126;
127 PUBLIC get_thread
128 PUBLIC get_tid
129 PUBLIC init_signal16
130 PUBLIC sig16_handler
131 PUBLIC touch
132 PUBLIC unwind
133
134;
135; The following variables are exported to other modules
136;
137 PUBLIC pipe_number
138 PUBLIC queue_number
139 PUBLIC sock_proc_count
140 PUBLIC old_sig16_handler
141
142;
143; The following functions are imported from other modules
144;
145 EXTRN build_arg_env:PROC
146 EXTRN copy_fork:PROC
147 EXTRN count_arg_env:PROC
148 EXTRN dos_call:PROC
149 EXTRN initialize1:PROC
150 EXTRN initialize2:PROC
151 EXTRN raise_from_16:PROC
152 EXTRN sys_call:PROC
153 EXTRN dll_init:PROC
154 EXTRN _DLL_InitTerm:PROC
155 EXTRN new_thread:PROC
156
157;
158; Import OS/2 API
159;
160 EXTRN DosUnwindException:PROC
161
162
163; ----------------------------------------------------------------------------
164; Macros
165; ----------------------------------------------------------------------------
166
167;
168; REG := pointer to thread data block
169;
170GET_THREAD MACRO REG
171 MOV REG, (TIB PTR FS:[0]).TIB_SYS_PTR
172 MOV REG, (TIB2 PTR [REG]).TID
173 MOV REG, threads[REG*4]
174 ENDM
175
176
177; ----------------------------------------------------------------------------
178; Code
179; ----------------------------------------------------------------------------
180
181;
182; This procedure is called by the startup code, see crt0.s. A pointer
183; to the layout table is passed on the stack.
184;
185; Doing this in C would be hard because we play dirty tricks with the stack.
186;
187emx_init: POP RET_ADDR ; Remove return address
188 POP EAX ; Pointer to layout table
189 MOV errout_handle, 2 ; Use stderr unless -!1 given
190 TEST (LAYOUT_TABLE PTR [EAX]).L_FLAGS, L_FLAG_DLL
191 JNZ DLL_INIT_1 ; Called by DLL startup code
192 MOV layout, EAX
193 CALL initialize1 ; First part of initialization
194 .IF fork_flag
195 MOV ESP, fork_stack_page
196 CALL copy_fork
197 .ENDIF
198 CALL USE_STACK ; Switch to new stack
199 CALL initialize2 ; Second part of initialization
200 .IF fork_flag
201 MOV EBP, fork_ebp
202 MOV I_EAX, 0 ; Make fork() return 0
203 MOV I_ECX, 0 ; Keep errno
204 JMP SYSCALL_RET
205 .ENDIF
206;
207; Compute number of bytes to be allocated for argv[] and envp[] and strings
208;
209 CALL count_arg_env
210;
211; Allocate space in the stack for the environment pointers and the arguments
212;
213 MOV ESI, ESP
214 SUB ESI, arg_size ; Argument strings are put here
215 MOV EDI, ESI
216 MOV EAX, arg_count
217 ADD EAX, env_count
218 ADD EAX, 2 ; Two NULL pointers
219 SHL EAX, 2
220 SUB EDI, EAX ; Tables are put here
221 AND EDI, NOT 3 ; Alignment
222 MOV BYTE PTR [EDI], 0 ; Stack probe
223 MOV ESP, EDI
224;
225; Build envp[] and argv[]
226;
227 PUSH EDI ; vec
228 PUSH ESI ; str
229 CALL build_arg_env ; build_arg_env (str, vec)
230 ADD ESP, 2 * 4
231;
232; Return to startup code
233;
234 JMP RET_ADDR
235
236;
237; We have been called by the DLL startup code, see dll0.s
238;
239 TALIGN 4
240DLL_INIT_1: CMP DWORD PTR [ESP+8], 0 ; Initialization?
241 JNE SHORT DLL_INIT_2 ; No -> skip
242 PUSH EAX
243 CALL dll_init
244 ADD ESP, 4
245DLL_INIT_2: JMP RET_ADDR
246
247
248;
249; Allocate space for the exception registration record on the stack.
250; If this is a forked process, adjust the stack pointer.
251;
252 TALIGN 4
253USE_STACK PROC
254 POP ECX ; Retrieve the return address
255 MOV ESI, stack_end ; EXC_REGISTER buffer must be
256 SUB ESI, SIZE EXC_REGISTER ; be in the stack
257 AND ESI, NOT 3 ; Align the stack pointer
258 MOV exc_reg_ptr, ESI
259 MOV AL, [ESI] ; Stack probe
260 .IF fork_flag
261 MOV ESI, fork_ebp
262 .ENDIF
263 MOV ESP, ESI ; Allocate space
264 JMP ECX
265 RET ; Avoid warning
266USE_STACK ENDP
267
268;
269; emx_syscall puts all the registers of the client process into the stack
270; using PUSHAD. The registers in the stack can then be accessed using the
271; following names. This can be used both for input and output.
272;
273I_EDI EQU (SYSCALL_FRAME PTR [EBP]).SC_EDI
274I_ESI EQU (SYSCALL_FRAME PTR [EBP]).SC_ESI
275I_EBP EQU (SYSCALL_FRAME PTR [EBP]).SC_EBP
276I_ESP EQU (SYSCALL_FRAME PTR [EBP]).SC_ESP
277I_EBX EQU (SYSCALL_FRAME PTR [EBP]).SC_EBX
278I_EDX EQU (SYSCALL_FRAME PTR [EBP]).SC_EDX
279I_ECX EQU (SYSCALL_FRAME PTR [EBP]).SC_ECX
280I_EAX EQU (SYSCALL_FRAME PTR [EBP]).SC_EAX
281I_EFLAGS EQU (SYSCALL_FRAME PTR [EBP]).SC_EFLAGS
282I_EIP EQU (SYSCALL_FRAME PTR [EBP]).SC_EIP
283
284I_AL EQU (BYTE PTR I_EAX+0)
285I_AH EQU (BYTE PTR I_EAX+1)
286I_CL EQU (BYTE PTR I_ECX+0)
287I_CH EQU (BYTE PTR I_ECX+1)
288I_DL EQU (BYTE PTR I_EDX+0)
289I_DH EQU (BYTE PTR I_EDX+1)
290
291;
292; syscall entry point. AH contains the function number, the other registers
293; contain arguments. Usually, CY will be set on return though not required
294; for all functions. The function numbers are somewhat similar to PC-DOS
295; function numbers -- it's simpler to use those numbers than inventing and
296; *remembering* new numbers (or using the(?) Unix syscall function numbers).
297; Using function names would be much more complex. In fact, even OS/2 uses
298; numbers (import by ordinal). See system.doc for details.
299;
300; As arguments are passed in registers (which may have been a bad idea),
301; this cannot be done in C.
302;
303 TALIGN 4
304emx_syscall: PUSHFD
305 PUSHAD ; Save all the registers
306 MOV EBP, ESP ; Make stack frame
307 CLD ; Don't trust anyone
308 GET_THREAD ESI ; ESI := pointer to thread data
309 TEST ESI, ESI ; Pointer valid?
310 JZ SHORT SYSCALL_ERRNO_1 ; No -> skip
311 ASSUME ESI:PTR THREAD_DATA
312 MOV EAX, [ESI].LAST_SYS_ERRNO; Get old error code
313 MOV [ESI].PREV_SYS_ERRNO, EAX ; Save it for __syserrno()
314 MOV [ESI].LAST_SYS_ERRNO, 0 ; Clear error code
315 ASSUME ESI:NOTHING
316SYSCALL_ERRNO_1:MOVZX EAX, I_AH ; Get function number
317 CMP AL, 7FH ; Special function?
318 JE SHORT SPECIAL ; Yes -> function code in AL
319 PUSH EBP ; f
320 CALL dos_call ; dos_call (f)
321 ADD ESP, 1 * 4
322SYSCALL_RET: POPAD ; Restore registers
323 POPFD
324 RET ; Return to user program
325
326 TALIGN 4
327SPECIAL: PUSH EBP ; f
328 CALL sys_call ; sys_call (f)
329 ADD ESP, 1 * 4
330 JMP SYSCALL_RET ; Restore registers and return
331
332;
333; Unwind exception handlers. Doing this in C would be hairy due to
334; DosUnwindException not returning and stack pointer adjustments done
335; or not done by the C compiler.
336;
337; void unwind (EXCEPTIONREGISTRATIONRECORD *registration,
338; EXCEPTIONREPORTRECORD *report);
339;
340;
341REGISTRATION EQU (DWORD PTR [EBP+2*4])
342REPORT EQU (DWORD PTR [EBP+3*4])
343 TALIGN 4
344unwind PROC
345 PUSH EBP ; Set up stack frame
346 MOV EBP, ESP
347 PUSH EBX ; Save registers
348 PUSH ESI
349 PUSH EDI
350 PUSH REPORT ; Report
351 PUSH OFFSET FLAT:UNWIND_1 ; Target address (jump there)
352 PUSH REGISTRATION ; Handler
353 MOV AL, 3
354 CALL DosUnwindException ; Does not return
355 TALIGN 4
356UNWIND_1: ADD ESP, 3 * 4 ; Remove arguments
357 POP EDI ; Restore registers
358 POP ESI
359 POP EBX
360 POP EBP
361 RET
362unwind ENDP
363
364
365;
366; Get pointer to thread data block. In assembler, we can do much better
367; (by using FS:0) than in C (using DosGetInfoBlocks).
368;
369 TALIGN 4
370get_thread PROC
371 GET_THREAD EAX
372 TEST EAX, EAX
373 JZ SHORT gt_new
374 RET
375
376; new_thread (tid, NULL)
377gt_new: CALL get_tid
378 PUSH 0 ; errnop
379 PUSH EAX ; tid
380 CALL new_thread
381 ADD ESP, 2*4
382 GET_THREAD EAX
383 RET
384get_thread ENDP
385
386
387;
388; Return the thread ID of the current thread.
389;
390 TALIGN 4
391get_tid PROC
392 MOV EAX, (TIB PTR FS:[0]).TIB_SYS_PTR
393 MOV EAX, (TIB2 PTR [EAX]).TID
394 RET
395get_tid ENDP
396
397
398;
399; Initialize variables for the 16-bit signal handler.
400;
401 TALIGN 4
402init_signal16 PROC
403 MOV SS32, SS
404 MOV FS32, FS
405 MOV DS32, DS
406 MOV ES32, ES
407 RET
408init_signal16 ENDP
409
410
411;
412; Touch each page in a range of addresses
413;
414; void touch (void *base, ULONG count);
415;
416; In: BASE Start address
417; COUNT Number of bytes
418;
419; This is required because DosRead seems not to be reentrant enough --
420; if it's used to read data into a page to be loaded from the .EXE file
421; (dumped heap), it's recursively called by the guard pageexception handler.
422; This call seems to disturb the first call, which will return a strange
423; `error code' (ESP plus some constant).
424;
425
426BASE EQU (DWORD PTR [EBP+2*4])
427COUNT EQU (DWORD PTR [EBP+3*4])
428 TALIGN 4
429touch PROC
430 PUSH EBP ; Make stack frame
431 MOV EBP, ESP
432 PUSH EBX ; Save register
433 MOV ECX, COUNT
434 JECXZ TOUCH_RET
435 MOV EBX, BASE
436 MOV AL, [EBX] ; Touch first page
437 MOV EAX, EBX ; Save start address
438 OR EBX, 0FFFH ; Move pointer to
439 INC EBX ; start of next page
440 SUB EBX, EAX ; Number of bytes skipped
441 SUB ECX, EBX ; Adjust counter
442 JBE SHORT TOUCH_RET ; Done -> return
443 ADD EBX, EAX ; Recompute pointer
444 TALIGN 4
445TOUCH_1: MOV AL, [EBX] ; Touch a page
446 ADD EBX, 1000H ; Move pointer to next page
447 SUB ECX, 1000H ; Adjust counter
448 JA SHORT TOUCH_1 ; More -> repeat
449TOUCH_RET: POP EBX ; Restore register
450 POP EBP ; Remove stack frame
451 RET ; Done
452touch ENDP
453
454
455;
456; 32-bit code called from 16-bit code: Raise signal CX
457;
458 TALIGN 4
459CALL32: MOVZX EAX, CX ; Signal number to EAX
460 PUSH EAX ; signo
461;
462; Raise signal (by calling)
463;
464 CALL raise_from_16 ; raise_from_16 (signo)
465 ADD ESP, 1 * 4
466;
467; Return to 16-bit code
468;
469 LSS SP, [ESP] ; Restore 16-bit stack
470 MOVZX ESP, SP ; Don't trust
471 JMP FAR PTR TEXT16:MODE32_RET
472
473TEXT32 ENDS
474
475; ----------------------------------------------------------------------------
476; 16-bit section
477; ----------------------------------------------------------------------------
478
479;
480; Import OS/2 API
481;
482
483 EXTRN _16_Dos16SetSigHandler:FAR16
484
485; ----------------------------------------------------------------------------
486; 16-bit data
487; ----------------------------------------------------------------------------
488
489BSS16 SEGMENT
490
491old_sig16_handler DWORD ?
492
493OLD_SIG_ACTION DWORD ?
494
495;
496; Saved segment registers of 32-bit mode, used for switching from
497; a 16-bit signal handler to 32-bit mode.
498;
499DS32 WORD ? ; The DS register of 32-bit mode
500ES32 WORD ? ; The ES register of 32-bit mode
501SS32 WORD ? ; The SS register of 32-bit mode
502FS32 WORD ? ; The FS register of 32-bit mode
503
504BSS16 ENDS
505
506; ----------------------------------------------------------------------------
507; 16-bit code
508; ----------------------------------------------------------------------------
509
510TEXT16 SEGMENT
511
512 ASSUME CS:TEXT16, DS:NOTHING, ES:NOTHING
513
514;
515; The 16-bit signal handler
516;
517SH_SIGNUM EQU (WORD PTR [BP+6]) ; Signal number
518SH_SIGARG EQU (WORD PTR [BP+8]) ; User-defined argument
519
520 ASSUME DS:NOTHING
521 TALIGN 4
522sig16_handler PROC FAR
523 PUSH BP ; Make stack frame
524 MOV BP, SP
525 PUSH DS ; Save DS
526 MOV AX, BSS16
527 MOV DS, AX ; Access our data segment
528 ASSUME DS:BSS16
529 PUSH CS ; Signal handler function
530 PUSH OFFSET TEXT16:sig16_handler
531 PUSH BSS16 ; Old signal handler function
532 PUSH OFFSET BSS16:old_sig16_handler
533 PUSH BSS16 ; Old signal handler action
534 PUSH OFFSET BSS16:OLD_SIG_ACTION
535 PUSH SIGA_ACKNOWLEDGE ; Action
536 PUSH SH_SIGNUM ; Signal
537 CALL _16_Dos16SetSigHandler ; Acknowledge signal
538 MOV CX, SH_SIGARG
539 CALL MODE32 ; Raise 32-bit signal
540 POP DS ; Restore DS
541 ASSUME DS:NOTHING
542 POP BP ; Remove stack frame
543 RET 4 ; Remove arguments
544sig16_handler ENDP
545
546 ASSUME DS:BSS16
547;
548; Call 32-bit code from 16-bit code
549;
550 TALIGN 4
551MODE32 PROC NEAR
552 PUSH FS
553 PUSH BP
554 MOV BP, SP
555 SUB SP, 4
556 AND SP, NOT 3 ; Align SP on a DWORD
557 MOV [BP-4], EAX
558 MOV AX, SP
559 PUSH SS
560 PUSH AX
561 MOV AX, SS
562 SHR AX, 3
563 SHL EAX, 16
564 MOV AX, SP
565 PUSH SS32
566 PUSH EAX
567 MOVZX ESP, SP
568;
569; Restore the FS register of 32-bit mode. FS:0 points to the TIB.
570; Fortunately, the selector seems to be the same for all the threads.
571; If each thread had its own selector, we would have a problem. The
572; only solution for this case I can think of is to store the FS register
573; in the thread-specific data block.
574;
575 MOV FS, FS32
576;
577; Restore the DS and ES registers of 32-bit mode.
578;
579 MOV ES, ES32
580 MOV DS, DS32
581 ASSUME DS:NOTHING
582 MOV EAX, [BP-4]
583 LSS ESP, [ESP]
584 JMP FAR PTR FLAT:CALL32
585;
586; Return here from CALL32.
587;
588 TALIGN 4
589MODE32_RET:: PUSH AX
590 MOV AX, BSS16
591 MOV DS, AX
592 ASSUME DS:BSS16
593 POP AX
594 MOV SP, BP
595 POP BP
596 POP FS
597 RET
598MODE32 ENDP
599
600TEXT16 ENDS
601
602 END _DLL_InitTerm
Note: See TracBrowser for help on using the repository browser.