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 | ;
|
---|
36 | MAX_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 | ;
|
---|
47 | SYSCALL_FRAME STRUCT
|
---|
48 | SC_EDI DWORD ?
|
---|
49 | SC_ESI DWORD ?
|
---|
50 | SC_EBP DWORD ?
|
---|
51 | SC_ESP DWORD ?
|
---|
52 | SC_EBX DWORD ?
|
---|
53 | SC_EDX DWORD ?
|
---|
54 | SC_ECX DWORD ?
|
---|
55 | SC_EAX DWORD ?
|
---|
56 | SC_EFLAGS DWORD ?
|
---|
57 | SC_EIP DWORD ?
|
---|
58 | SYSCALL_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 | ;
|
---|
65 | THREAD_DATA STRUCT
|
---|
66 | LAST_SYS_ERRNO DWORD ? ; Error code for last syscall
|
---|
67 | PREV_SYS_ERRNO DWORD ? ; Previous value of the above
|
---|
68 | ; ...and other fields, which are omitted here
|
---|
69 | THREAD_DATA ENDS
|
---|
70 |
|
---|
71 | ; ----------------------------------------------------------------------------
|
---|
72 | ; Data
|
---|
73 | ; ----------------------------------------------------------------------------
|
---|
74 |
|
---|
75 | BSS32 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 | ;
|
---|
95 | RET_ADDR DWORD ? ; Return address
|
---|
96 |
|
---|
97 | BSS32 ENDS
|
---|
98 |
|
---|
99 | ; ----------------------------------------------------------------------------
|
---|
100 | ; Solo data
|
---|
101 | ; ----------------------------------------------------------------------------
|
---|
102 |
|
---|
103 | COMMON32 SEGMENT
|
---|
104 | pipe_number DWORD ?
|
---|
105 | queue_number DWORD ?
|
---|
106 | sock_proc_count DWORD MAX_SOCKETS DUP (?)
|
---|
107 | COMMON32 ENDS
|
---|
108 |
|
---|
109 |
|
---|
110 | ; ----------------------------------------------------------------------------
|
---|
111 | ; The code segment
|
---|
112 | ; ----------------------------------------------------------------------------
|
---|
113 |
|
---|
114 | TEXT32 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 | ;
|
---|
170 | GET_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 | ;
|
---|
187 | emx_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
|
---|
240 | DLL_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
|
---|
245 | DLL_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
|
---|
253 | USE_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
|
---|
266 | USE_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 | ;
|
---|
273 | I_EDI EQU (SYSCALL_FRAME PTR [EBP]).SC_EDI
|
---|
274 | I_ESI EQU (SYSCALL_FRAME PTR [EBP]).SC_ESI
|
---|
275 | I_EBP EQU (SYSCALL_FRAME PTR [EBP]).SC_EBP
|
---|
276 | I_ESP EQU (SYSCALL_FRAME PTR [EBP]).SC_ESP
|
---|
277 | I_EBX EQU (SYSCALL_FRAME PTR [EBP]).SC_EBX
|
---|
278 | I_EDX EQU (SYSCALL_FRAME PTR [EBP]).SC_EDX
|
---|
279 | I_ECX EQU (SYSCALL_FRAME PTR [EBP]).SC_ECX
|
---|
280 | I_EAX EQU (SYSCALL_FRAME PTR [EBP]).SC_EAX
|
---|
281 | I_EFLAGS EQU (SYSCALL_FRAME PTR [EBP]).SC_EFLAGS
|
---|
282 | I_EIP EQU (SYSCALL_FRAME PTR [EBP]).SC_EIP
|
---|
283 |
|
---|
284 | I_AL EQU (BYTE PTR I_EAX+0)
|
---|
285 | I_AH EQU (BYTE PTR I_EAX+1)
|
---|
286 | I_CL EQU (BYTE PTR I_ECX+0)
|
---|
287 | I_CH EQU (BYTE PTR I_ECX+1)
|
---|
288 | I_DL EQU (BYTE PTR I_EDX+0)
|
---|
289 | I_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
|
---|
304 | emx_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
|
---|
316 | SYSCALL_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
|
---|
322 | SYSCALL_RET: POPAD ; Restore registers
|
---|
323 | POPFD
|
---|
324 | RET ; Return to user program
|
---|
325 |
|
---|
326 | TALIGN 4
|
---|
327 | SPECIAL: 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 | ;
|
---|
341 | REGISTRATION EQU (DWORD PTR [EBP+2*4])
|
---|
342 | REPORT EQU (DWORD PTR [EBP+3*4])
|
---|
343 | TALIGN 4
|
---|
344 | unwind 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
|
---|
356 | UNWIND_1: ADD ESP, 3 * 4 ; Remove arguments
|
---|
357 | POP EDI ; Restore registers
|
---|
358 | POP ESI
|
---|
359 | POP EBX
|
---|
360 | POP EBP
|
---|
361 | RET
|
---|
362 | unwind 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
|
---|
370 | get_thread PROC
|
---|
371 | GET_THREAD EAX
|
---|
372 | TEST EAX, EAX
|
---|
373 | JZ SHORT gt_new
|
---|
374 | RET
|
---|
375 |
|
---|
376 | ; new_thread (tid, NULL)
|
---|
377 | gt_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
|
---|
384 | get_thread ENDP
|
---|
385 |
|
---|
386 |
|
---|
387 | ;
|
---|
388 | ; Return the thread ID of the current thread.
|
---|
389 | ;
|
---|
390 | TALIGN 4
|
---|
391 | get_tid PROC
|
---|
392 | MOV EAX, (TIB PTR FS:[0]).TIB_SYS_PTR
|
---|
393 | MOV EAX, (TIB2 PTR [EAX]).TID
|
---|
394 | RET
|
---|
395 | get_tid ENDP
|
---|
396 |
|
---|
397 |
|
---|
398 | ;
|
---|
399 | ; Initialize variables for the 16-bit signal handler.
|
---|
400 | ;
|
---|
401 | TALIGN 4
|
---|
402 | init_signal16 PROC
|
---|
403 | MOV SS32, SS
|
---|
404 | MOV FS32, FS
|
---|
405 | MOV DS32, DS
|
---|
406 | MOV ES32, ES
|
---|
407 | RET
|
---|
408 | init_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 |
|
---|
426 | BASE EQU (DWORD PTR [EBP+2*4])
|
---|
427 | COUNT EQU (DWORD PTR [EBP+3*4])
|
---|
428 | TALIGN 4
|
---|
429 | touch 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
|
---|
445 | TOUCH_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
|
---|
449 | TOUCH_RET: POP EBX ; Restore register
|
---|
450 | POP EBP ; Remove stack frame
|
---|
451 | RET ; Done
|
---|
452 | touch ENDP
|
---|
453 |
|
---|
454 |
|
---|
455 | ;
|
---|
456 | ; 32-bit code called from 16-bit code: Raise signal CX
|
---|
457 | ;
|
---|
458 | TALIGN 4
|
---|
459 | CALL32: 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 |
|
---|
473 | TEXT32 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 |
|
---|
489 | BSS16 SEGMENT
|
---|
490 |
|
---|
491 | old_sig16_handler DWORD ?
|
---|
492 |
|
---|
493 | OLD_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 | ;
|
---|
499 | DS32 WORD ? ; The DS register of 32-bit mode
|
---|
500 | ES32 WORD ? ; The ES register of 32-bit mode
|
---|
501 | SS32 WORD ? ; The SS register of 32-bit mode
|
---|
502 | FS32 WORD ? ; The FS register of 32-bit mode
|
---|
503 |
|
---|
504 | BSS16 ENDS
|
---|
505 |
|
---|
506 | ; ----------------------------------------------------------------------------
|
---|
507 | ; 16-bit code
|
---|
508 | ; ----------------------------------------------------------------------------
|
---|
509 |
|
---|
510 | TEXT16 SEGMENT
|
---|
511 |
|
---|
512 | ASSUME CS:TEXT16, DS:NOTHING, ES:NOTHING
|
---|
513 |
|
---|
514 | ;
|
---|
515 | ; The 16-bit signal handler
|
---|
516 | ;
|
---|
517 | SH_SIGNUM EQU (WORD PTR [BP+6]) ; Signal number
|
---|
518 | SH_SIGARG EQU (WORD PTR [BP+8]) ; User-defined argument
|
---|
519 |
|
---|
520 | ASSUME DS:NOTHING
|
---|
521 | TALIGN 4
|
---|
522 | sig16_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
|
---|
544 | sig16_handler ENDP
|
---|
545 |
|
---|
546 | ASSUME DS:BSS16
|
---|
547 | ;
|
---|
548 | ; Call 32-bit code from 16-bit code
|
---|
549 | ;
|
---|
550 | TALIGN 4
|
---|
551 | MODE32 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
|
---|
589 | MODE32_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
|
---|
598 | MODE32 ENDP
|
---|
599 |
|
---|
600 | TEXT16 ENDS
|
---|
601 |
|
---|
602 | END _DLL_InitTerm
|
---|