| 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
|
|---|