| 1 | ;
|
|---|
| 2 | ; EMX.ASM -- Main module for emx.exe
|
|---|
| 3 | ;
|
|---|
| 4 | ; Copyright (c) 1991-1999 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 | ; <START_OF_EXCEPTION>
|
|---|
| 24 | ; As a special exception, if you bind emx.exe to an executable file
|
|---|
| 25 | ; (using emxbind), this does not cause the resulting executable file
|
|---|
| 26 | ; to be covered by the GNU General Public License. This exception
|
|---|
| 27 | ; does not however invalidate any other reasons why the executable
|
|---|
| 28 | ; file might be covered by the GNU General Public License. However,
|
|---|
| 29 | ; if you bind a modified copy of emx.exe to an executable file, you
|
|---|
| 30 | ; have to include source code for emx.exe.
|
|---|
| 31 | ;
|
|---|
| 32 | ; If you modify this file, you have to remove the reference to the
|
|---|
| 33 | ; special exception from all the source files and replace the text
|
|---|
| 34 | ; between the outer <START_OF_EXCEPTION> and <END_OF_EXCEPTION> markers
|
|---|
| 35 | ; with the following paragraph (which currently does not apply as you
|
|---|
| 36 | ; have not modified this file):
|
|---|
| 37 | ;
|
|---|
| 38 | ; As a special exception, if you bind emx.exe to an executable file
|
|---|
| 39 | ; (using emxbind), this does not cause the resulting executable file
|
|---|
| 40 | ; to be covered by the GNU General Public License. The source code
|
|---|
| 41 | ; for emx.exe must be distributed with the executable file. This
|
|---|
| 42 | ; exception does not however invalidate any other reasons why the
|
|---|
| 43 | ; executable file might be covered by the GNU General Public License.
|
|---|
| 44 | ; <END_OF_EXCEPTION>
|
|---|
| 45 | ;
|
|---|
| 46 |
|
|---|
| 47 | INCLUDE EMX.INC
|
|---|
| 48 | INCLUDE TABLES.INC
|
|---|
| 49 | INCLUDE SEGMENTS.INC
|
|---|
| 50 | INCLUDE PAGING.INC
|
|---|
| 51 | INCLUDE OPRINT.INC
|
|---|
| 52 | INCLUDE VPRINT.INC
|
|---|
| 53 | INCLUDE MEMORY.INC
|
|---|
| 54 | INCLUDE PMIO.INC
|
|---|
| 55 | INCLUDE SIGNAL.INC
|
|---|
| 56 | INCLUDE PROCESS.INC
|
|---|
| 57 | INCLUDE SWAPPER.INC
|
|---|
| 58 | INCLUDE EXCEPT.INC
|
|---|
| 59 | INCLUDE RMINT.INC
|
|---|
| 60 | INCLUDE PMINT.INC
|
|---|
| 61 | INCLUDE VCPI.INC
|
|---|
| 62 | INCLUDE DPMI.INC
|
|---|
| 63 | INCLUDE RPRINT.INC
|
|---|
| 64 | INCLUDE DEBUG.INC
|
|---|
| 65 | INCLUDE LOADER.INC
|
|---|
| 66 | INCLUDE XMS.INC
|
|---|
| 67 | INCLUDE A20.INC
|
|---|
| 68 | INCLUDE TERMIO.INC
|
|---|
| 69 | INCLUDE VERSION.INC
|
|---|
| 70 | INCLUDE HEADERS.INC
|
|---|
| 71 | INCLUDE PMINT.INC
|
|---|
| 72 | INCLUDE OPTIONS.INC
|
|---|
| 73 | INCLUDE FILEIO.INC
|
|---|
| 74 |
|
|---|
| 75 | PUBLIC SV_TOS, RM_TOS
|
|---|
| 76 | PUBLIC FP_FLAG, FP_TMP, DOS_MAJOR, DOS_MINOR, ENV_EMXOPT
|
|---|
| 77 | PUBLIC CMDL_OPTIONS, ENV_PATH, ENV_EMXPATH
|
|---|
| 78 | PUBLIC PROT1
|
|---|
| 79 | PUBLIC CLEANUP, EXIT, RM_OUT_OF_MEM
|
|---|
| 80 |
|
|---|
| 81 | SV_DATA SEGMENT
|
|---|
| 82 |
|
|---|
| 83 | ;
|
|---|
| 84 | ; Names of environment variables
|
|---|
| 85 | ;
|
|---|
| 86 | $PATH BYTE "PATH", 0
|
|---|
| 87 | $EMXPATH BYTE "EMXPATH", 0
|
|---|
| 88 | $TMP BYTE "TMP", 0
|
|---|
| 89 | $EMXTMP BYTE "EMXTMP", 0
|
|---|
| 90 | $EMXOPT BYTE "EMXOPT", 0
|
|---|
| 91 |
|
|---|
| 92 | ;
|
|---|
| 93 | ; Program segment prefix and environment
|
|---|
| 94 | ;
|
|---|
| 95 | DALIGN 2
|
|---|
| 96 |
|
|---|
| 97 | EMXL_SEG WORD 0 ; PSP segment of emxl
|
|---|
| 98 | EMX_PSP WORD ? ; Our PSP segment
|
|---|
| 99 | ENV_SEG WORD ? ; Environment segment
|
|---|
| 100 | ENV_PATH WORD ? ; Pointer to PATH value
|
|---|
| 101 | ENV_EMXPATH WORD ? ; Pointer to EMXPATH value
|
|---|
| 102 | ENV_EMXOPT WORD ? ; Pointer to EMXOPT value
|
|---|
| 103 | ENV_TOTAL_SIZE WORD ? ; Size of environment, w/ exe
|
|---|
| 104 |
|
|---|
| 105 | ;
|
|---|
| 106 | ; The arguments of the initial process
|
|---|
| 107 | ;
|
|---|
| 108 | ARG_STRINGS BYTE 256 DUP (?) ; Arguments
|
|---|
| 109 |
|
|---|
| 110 | ;
|
|---|
| 111 | ; Floating point
|
|---|
| 112 | ;
|
|---|
| 113 | FP_TMP WORD ? ; 287/387 CW or SW
|
|---|
| 114 | FP_FLAG BYTE FP_NO ; No coprocessor
|
|---|
| 115 |
|
|---|
| 116 | ;
|
|---|
| 117 | ; This field is copied from HDR_SEG to SV_DATA
|
|---|
| 118 | ;
|
|---|
| 119 | BIND_FLAG BYTE ? ; Bound application
|
|---|
| 120 |
|
|---|
| 121 | ;
|
|---|
| 122 | ; DOS version
|
|---|
| 123 | ;
|
|---|
| 124 | DOS_MAJOR BYTE ?
|
|---|
| 125 | DOS_MINOR BYTE ?
|
|---|
| 126 |
|
|---|
| 127 | ;
|
|---|
| 128 | ; Options copied from the command line. Non-option arguments don't
|
|---|
| 129 | ; appear hear. After starting the first process, CMDL_OPTIONS is
|
|---|
| 130 | ; cleared by zeroing the first byte.
|
|---|
| 131 | ;
|
|---|
| 132 | CMDL_OPTIONS BYTE 64 DUP (0)
|
|---|
| 133 |
|
|---|
| 134 | ;
|
|---|
| 135 | ; Messages
|
|---|
| 136 | ;
|
|---|
| 137 | $WRONG_CPU BYTE "This program requires an 80386 CPU", CR, LF, 0
|
|---|
| 138 | $WRONG_OPSYS BYTE "This program does not run in DOS mode of OS/2"
|
|---|
| 139 | BYTE CR, LF, 0
|
|---|
| 140 | $DOS_VERSION BYTE "This program requires DOS 3.0 or later", CR, LF, 0
|
|---|
| 141 | $NO_A20 BYTE "Cannot enable A20", CR, LF, 0
|
|---|
| 142 | $RM_OUT_OF_MEM BYTE "Out of memory (RM)", CR, LF, 0
|
|---|
| 143 |
|
|---|
| 144 | SV_DATA ENDS
|
|---|
| 145 |
|
|---|
| 146 |
|
|---|
| 147 | ;
|
|---|
| 148 | ; This area will be patched by emxbind when using emx.exe as DOS stub.
|
|---|
| 149 | ;
|
|---|
| 150 | HDR_SEG SEGMENT
|
|---|
| 151 | PATCH LABEL BIND_HEADER
|
|---|
| 152 | BYTE "emx ", VERSION, 0
|
|---|
| 153 | BYTE (SIZE BIND_HEADER - HDR_VERSION_LEN) DUP (0)
|
|---|
| 154 | HDR_SEG ENDS
|
|---|
| 155 |
|
|---|
| 156 |
|
|---|
| 157 | .386P
|
|---|
| 158 |
|
|---|
| 159 | SV_CODE SEGMENT
|
|---|
| 160 |
|
|---|
| 161 | ASSUME CS:SV_CODE, DS:NOTHING
|
|---|
| 162 |
|
|---|
| 163 | ;
|
|---|
| 164 | ; This is the proteced mode entry point
|
|---|
| 165 | ;
|
|---|
| 166 | PROT1 LABEL FAR
|
|---|
| 167 | MOV AX, G_SV_DATA_SEL
|
|---|
| 168 | MOV DS, AX
|
|---|
| 169 | ASSUME DS:SV_DATA
|
|---|
| 170 | MOV ES, AX
|
|---|
| 171 | MOV FS, AX
|
|---|
| 172 | MOV GS, AX
|
|---|
| 173 | MOV AX, G_SV_STACK_SEL
|
|---|
| 174 | MOV SS, AX
|
|---|
| 175 | LEA ESP, SV_TOS
|
|---|
| 176 | AND TSS_BUSY, NOT 2
|
|---|
| 177 | MOV AX, G_TSS_SEL
|
|---|
| 178 | LTR AX
|
|---|
| 179 | ;
|
|---|
| 180 | ; This must be done before any interrupt can be handled
|
|---|
| 181 | ; (SLDT, LLDT in PMINT.ASM)
|
|---|
| 182 | ;
|
|---|
| 183 | MOV AX, G_LDT_SEL ; Minimal LDT
|
|---|
| 184 | LLDT AX ; Load LDTR
|
|---|
| 185 | ;
|
|---|
| 186 | ; Protected mode established
|
|---|
| 187 | ;
|
|---|
| 188 | CALL DEBUG_INIT
|
|---|
| 189 | XOR EAX, EAX
|
|---|
| 190 | MOV DR6, EAX ; Clear debug status register
|
|---|
| 191 | CALL INIT_FP
|
|---|
| 192 | ;
|
|---|
| 193 | ; From now onwards, we can switch back to real mode
|
|---|
| 194 | ;
|
|---|
| 195 | ; Enable paging
|
|---|
| 196 | ;
|
|---|
| 197 | MOV PAGING, 1 ; Paging enabled
|
|---|
| 198 | CMP VCPI_FLAG, FALSE ; VCPI?
|
|---|
| 199 | JNE SHORT PROT2 ; Yes -> paging already enabled
|
|---|
| 200 | MOV EAX, PAGE_DIR_PHYS
|
|---|
| 201 | MOV CR3, EAX ; Load CR3
|
|---|
| 202 | MOV EAX, CR0
|
|---|
| 203 | OR EAX, CR0_PG ; Enable paging
|
|---|
| 204 | MOV CR0, EAX
|
|---|
| 205 | ;
|
|---|
| 206 | ; Further initializations
|
|---|
| 207 | ;
|
|---|
| 208 | PROT2: STI ; Enable interrupts
|
|---|
| 209 | CALL INIT_LIN_MAP ; Enable segment creation
|
|---|
| 210 | CALL INIT_PAGE_BMAP ; Initialize freed page bitmap
|
|---|
| 211 | CALL INIT_SWAP ; Enable swapping
|
|---|
| 212 | CALL INIT_TSS ; Initialize new TSS
|
|---|
| 213 | CALL INIT_DBCS ; Get DBCS lead bytes
|
|---|
| 214 | ;
|
|---|
| 215 | ; Create GDT entry for environment segment
|
|---|
| 216 | ;
|
|---|
| 217 | MOVZX EBX, ENV_SEG
|
|---|
| 218 | SHL EBX, 4
|
|---|
| 219 | MOVZX ECX, ENV_TOTAL_SIZE
|
|---|
| 220 | LEA SI, G_ENV_DESC
|
|---|
| 221 | MOV AX, A_DATA32 OR DPL_0
|
|---|
| 222 | CALL CREATE_SEG
|
|---|
| 223 | ;
|
|---|
| 224 | ; Initialize termio structure for stdin (global data for all processes)
|
|---|
| 225 | ;
|
|---|
| 226 | LEA BX, STDIN_TERMIO
|
|---|
| 227 | CALL TERMIO_INIT
|
|---|
| 228 | MOV STDIN_FL, 0
|
|---|
| 229 | ;
|
|---|
| 230 | ; Load program
|
|---|
| 231 | ;
|
|---|
| 232 | LEA SI, ARG_STRINGS + 1 ; argv[0]
|
|---|
| 233 | CALL FIND_EXEC
|
|---|
| 234 | MOV NP1.NP_FNAME_OFF, EDX
|
|---|
| 235 | MOV NP1.NP_FNAME_SEL, DS
|
|---|
| 236 | LEA AX, PROC0 ; Dummy parent process
|
|---|
| 237 | MOV NP1.NP_PARENT, AX
|
|---|
| 238 | MOV NP1.NP_FPROC, AX
|
|---|
| 239 | MOV NP1.NP_MODE1, NP_SPAWN_SYNC
|
|---|
| 240 | MOV NP1.NP_MODE2, 0
|
|---|
| 241 | LEA SI, NP1 ; Arguments
|
|---|
| 242 | CALL NEW_PROCESS ; Load the program
|
|---|
| 243 | OR AX, AX ; Ok?
|
|---|
| 244 | JZ SHORT LOAD3
|
|---|
| 245 | CALL OTEXT ; Display error message
|
|---|
| 246 | MOV AX, 4C01H ; Quit
|
|---|
| 247 | INT 21H
|
|---|
| 248 | JMP SHORT $ ; Never reached
|
|---|
| 249 |
|
|---|
| 250 | ASSUME DI:PTR PROCESS
|
|---|
| 251 | LOAD3: MOV CMDL_OPTIONS[0], 0 ; Ignore options from now on
|
|---|
| 252 | MOV [DI].P_STATUS, PS_RUN ; Process is running!
|
|---|
| 253 | MOV PROCESS_PTR, DI ; Current process (I/O etc.)
|
|---|
| 254 | MOV PROCESS_SIG, DI ; Current process (Ctrl-Break)
|
|---|
| 255 | ;
|
|---|
| 256 | ; Now DS:DI points to the process table entry
|
|---|
| 257 | ;
|
|---|
| 258 | ; Switch to 32 bit code/data
|
|---|
| 259 | ;
|
|---|
| 260 | CMP STEP_FLAG, FALSE ; Debugging program?
|
|---|
| 261 | JE SHORT DISPATCH_1 ; No -> skip
|
|---|
| 262 | MOV DX, L_CODE_SEL ; Set breakpoint
|
|---|
| 263 | MOV EAX, [DI].P_ENTRY_POINT ; on entry point
|
|---|
| 264 | CALL SET_BREAKPOINT
|
|---|
| 265 | CALL INS_BREAKPOINTS
|
|---|
| 266 | DISPATCH_1: MOV EAX, 0002H ; This bit is always 1
|
|---|
| 267 | PUSH EAX
|
|---|
| 268 | POPFD ; Clear all flag bits
|
|---|
| 269 | LLDT [DI].P_LDT ; Use LDT
|
|---|
| 270 | ; Stack empty!
|
|---|
| 271 | MOV EAX, L_DATA_SEL
|
|---|
| 272 | PUSH EAX ; SS
|
|---|
| 273 | MOV EBX, [DI].P_ESP
|
|---|
| 274 | PUSH EBX ; ESP
|
|---|
| 275 | MOV EAX, 0202H ; IOPL=0, IF=1
|
|---|
| 276 | CMP STEP_FLAG, FALSE ; Single stepping?
|
|---|
| 277 | JE SHORT DISPATCH_2 ; No -> skip
|
|---|
| 278 | OR EAX, FLAG_TF ; Set trap flag
|
|---|
| 279 | DISPATCH_2: PUSH EAX ; EFLAGS
|
|---|
| 280 | MOV EAX, L_CODE_SEL
|
|---|
| 281 | PUSH EAX ; CS
|
|---|
| 282 | MOV EBX, [DI].P_ENTRY_POINT
|
|---|
| 283 | PUSH EBX ; EIP
|
|---|
| 284 | MOV AX, L_DATA_SEL
|
|---|
| 285 | MOV DS, AX
|
|---|
| 286 | ASSUME DS:NOTHING
|
|---|
| 287 | MOV ES, AX
|
|---|
| 288 | MOV FS, AX
|
|---|
| 289 | MOV GS, AX
|
|---|
| 290 | IRETD
|
|---|
| 291 |
|
|---|
| 292 | ASSUME DI:NOTHING
|
|---|
| 293 |
|
|---|
| 294 | ;
|
|---|
| 295 | ; We must not use FWAIT if there is no coprocessor. We use this loop
|
|---|
| 296 | ; instead.
|
|---|
| 297 | ;
|
|---|
| 298 | DELAY_FP MACRO
|
|---|
| 299 | MOV ECX, 50
|
|---|
| 300 | LOOP $
|
|---|
| 301 | ENDM
|
|---|
| 302 |
|
|---|
| 303 | ;
|
|---|
| 304 | ; Initialize CR0 for floating point math (287, 387, or emulator)
|
|---|
| 305 | ;
|
|---|
| 306 | ; Note: ET set by reset?
|
|---|
| 307 | ;
|
|---|
| 308 | ASSUME DS:SV_DATA
|
|---|
| 309 | INIT_FP PROC NEAR
|
|---|
| 310 | MOV EAX, CR0 ; Get current CR0
|
|---|
| 311 | AND EAX, CR0_FPU ; Keep only FPU related bits
|
|---|
| 312 | MOV RM_CR0, EAX ; Save it
|
|---|
| 313 | MOV EAX, CR0 ; Get current CR0
|
|---|
| 314 | AND EAX, NOT (CR0_TS OR CR0_EM)
|
|---|
| 315 | OR EAX, CR0_MP ; Assume FPU present
|
|---|
| 316 | MOV CR0, EAX
|
|---|
| 317 | ;
|
|---|
| 318 | ; Now check for coprocessor
|
|---|
| 319 | ;
|
|---|
| 320 | CMP FP_IGNORE, FALSE ; Check for coprocessor?
|
|---|
| 321 | JNE SHORT INIT_FP1 ; No -> skip check
|
|---|
| 322 | FNINIT
|
|---|
| 323 | DELAY_FP ; Delay
|
|---|
| 324 | MOV FP_TMP, 0 ; 387 FNINIT sets CW to 037FH
|
|---|
| 325 | FNSTCW FP_TMP ; Copy CW to memory
|
|---|
| 326 | DELAY_FP ; Delay
|
|---|
| 327 | MOV AX, FP_TMP ; Now check CW
|
|---|
| 328 | AND AX, 0F3FH ; Keep PC and exception masks
|
|---|
| 329 | CMP AX, 033FH ; Initialized?
|
|---|
| 330 | JNE SHORT INIT_FP1 ; No -> no x87 coprocessor
|
|---|
| 331 | MOV FP_TMP, 0FFFFH ; 387 FNINIT: SW &= 0x4700
|
|---|
| 332 | FNSTSW FP_TMP ; Copy SW to memory
|
|---|
| 333 | DELAY_FP ; Delay
|
|---|
| 334 | TEST FP_TMP, NOT 47C0H ; Initialized?
|
|---|
| 335 | JNZ SHORT INIT_FP1 ; No -> no x87 coprocessor
|
|---|
| 336 | ;
|
|---|
| 337 | ; We have found *some* coprocessor (87, 287, 387, ...)
|
|---|
| 338 | ;
|
|---|
| 339 | ; If 1/0 equals -(1/0), we are dealing with a 287: FNINIT sets the 287
|
|---|
| 340 | ; to projective mode, ie, -inf = +inf, whereas the 387 always uses
|
|---|
| 341 | ; affine mode (-inf < +inf).
|
|---|
| 342 | ;
|
|---|
| 343 | MOV FP_FLAG, FP_287 ; ST ST(1)
|
|---|
| 344 | FLD1 ; 1.0
|
|---|
| 345 | FLDZ ; 0.0 1.0
|
|---|
| 346 | FDIV ; +inf
|
|---|
| 347 | FLD ST ; +inf +inf
|
|---|
| 348 | FCHS ; -inf +inf (287: +inf +inf)
|
|---|
| 349 | FCOMPP ; (stack empty)
|
|---|
| 350 | FSTSW AX ; Status to AX
|
|---|
| 351 | SAHF ; 387: NZ, 287: ZR
|
|---|
| 352 | JE SHORT INIT_FP1 ; 287 found -> skip
|
|---|
| 353 | MOV FP_FLAG, FP_387 ; 387 found
|
|---|
| 354 | INIT_FP1:
|
|---|
| 355 | ;
|
|---|
| 356 | ; Now set CR0
|
|---|
| 357 | ;
|
|---|
| 358 | MOV EAX, CR0
|
|---|
| 359 | AND EAX, NOT CR0_FPU
|
|---|
| 360 | CMP FP_FLAG, FP_387 ; 387 coprocessor?
|
|---|
| 361 | JNE SHORT IFP_EMU ; No -> setup for emulation
|
|---|
| 362 | OR EAX, CR0_TS OR CR0_MP ; Task switched, math present
|
|---|
| 363 | JMP SHORT IFP_SET
|
|---|
| 364 | IFP_EMU: OR EAX, CR0_TS OR CR0_EM ; Task switched, emulate
|
|---|
| 365 | IFP_SET: MOV CR0, EAX ; Set CR0
|
|---|
| 366 | AND EAX, CR0_FPU ; Keep only FPU bits
|
|---|
| 367 | MOV PM_CR0, EAX ; Save for switching to PM
|
|---|
| 368 | RET ; Done
|
|---|
| 369 | INIT_FP ENDP
|
|---|
| 370 |
|
|---|
| 371 | ;
|
|---|
| 372 | ; Initialize DBCS lead byte table. Note that we can't call GET_DBCS_LEAD
|
|---|
| 373 | ; directly.
|
|---|
| 374 | ;
|
|---|
| 375 | INIT_DBCS PROC NEAR
|
|---|
| 376 | PUSH DS
|
|---|
| 377 | MOV EDX, 0
|
|---|
| 378 | MOV DS, DX
|
|---|
| 379 | MOV AX, 7F5AH
|
|---|
| 380 | INT 21H
|
|---|
| 381 | POP DS
|
|---|
| 382 | RET
|
|---|
| 383 | INIT_DBCS ENDP
|
|---|
| 384 |
|
|---|
| 385 | SV_CODE ENDS
|
|---|
| 386 |
|
|---|
| 387 |
|
|---|
| 388 | SV_STACK SEGMENT
|
|---|
| 389 | WORD 2048 DUP (?)
|
|---|
| 390 | SV_TOS LABEL WORD
|
|---|
| 391 | SV_STACK ENDS
|
|---|
| 392 |
|
|---|
| 393 |
|
|---|
| 394 |
|
|---|
| 395 | RM_STACK SEGMENT
|
|---|
| 396 | WORD 1024 DUP (?)
|
|---|
| 397 | RM_TOS LABEL WORD
|
|---|
| 398 | RM_STACK ENDS
|
|---|
| 399 |
|
|---|
| 400 |
|
|---|
| 401 | INIT_CODE SEGMENT
|
|---|
| 402 |
|
|---|
| 403 | ASSUME CS:INIT_CODE
|
|---|
| 404 |
|
|---|
| 405 |
|
|---|
| 406 |
|
|---|
| 407 | ;
|
|---|
| 408 | ; Use backward jump to this code to make sure the prefetch queue
|
|---|
| 409 | ; will be flushed
|
|---|
| 410 | ;
|
|---|
| 411 | START_4: JMPF16 G_SV_CODE_SEL, PROT1
|
|---|
| 412 |
|
|---|
| 413 | ;
|
|---|
| 414 | ; Entrypoint
|
|---|
| 415 | ;
|
|---|
| 416 |
|
|---|
| 417 | ASSUME DS:NOTHING
|
|---|
| 418 | .8086
|
|---|
| 419 | START: MOV AX, SV_DATA
|
|---|
| 420 | MOV DS, AX
|
|---|
| 421 | ASSUME DS:SV_DATA
|
|---|
| 422 | MOV EMX_PSP, ES ; Save PSP segment
|
|---|
| 423 |
|
|---|
| 424 | CALL EMXBIND
|
|---|
| 425 | CALL CHECK_CPU ; 386 CPU required
|
|---|
| 426 | CALL CHECK_OPSYS ; Check operating system
|
|---|
| 427 |
|
|---|
| 428 | .386P
|
|---|
| 429 |
|
|---|
| 430 | CALL CHECK_EMXL ; Run by emxl?
|
|---|
| 431 | CALL ENVIRONMENT ; Read environment
|
|---|
| 432 | CALL ARGS ; Read command line arguments
|
|---|
| 433 | CALL GET_PATH ; Get PATH/EMXPATH variables
|
|---|
| 434 | CALL GET_TMP ; Get TMP/EMXTMP variables
|
|---|
| 435 | CALL CHECK_DV ; Check for DESQview
|
|---|
| 436 | CALL PROCESS_INIT ; Initialize emx processes
|
|---|
| 437 | CALL HOOK_INT ; Hook interrupts
|
|---|
| 438 | CALL CHECK_VCPI ; Check for VCPI
|
|---|
| 439 | CALL CHECK_DPMI ; Check for DPMI
|
|---|
| 440 | ; (After CHECK_VCPI)
|
|---|
| 441 | CALL CHECK_VM
|
|---|
| 442 | CALL CHECK_XMS ; Check for XMS
|
|---|
| 443 | ; (After CHECK_VCPI)
|
|---|
| 444 | CALL INIT_TERMIO ; Get keyboard type
|
|---|
| 445 | CALL INIT_A20 ; Find out which machine
|
|---|
| 446 | ; (after CHECK_XMS)
|
|---|
| 447 | CALL INIT_BUFFER ; Allocate buffers
|
|---|
| 448 | CALL INIT_MEMORY ; Initialize memory allocation
|
|---|
| 449 | CALL INIT_PAGING ; Initialize page tables
|
|---|
| 450 | ; (after CHECK_VCPI, INIT_MEMORY)
|
|---|
| 451 | CALL INIT_ADDR ; Initialize physical/linear
|
|---|
| 452 | ; addresses (after INIT_MEMORY,
|
|---|
| 453 | ; INIT_PAGING)
|
|---|
| 454 | CALL INIT_MEM_PHYS
|
|---|
| 455 | CALL INIT_VIDEO ; Init video segments
|
|---|
| 456 | CMP XMS_FLAG, FALSE
|
|---|
| 457 | JE SHORT START_2
|
|---|
| 458 | CALL INIT_XMS ; After CHECK_VCPI, INIT_MEMORY
|
|---|
| 459 | START_2: CALL INIT_BASES ; After INIT_PAGING
|
|---|
| 460 | CMP HIMEM_COUNT, 0 ; Extended memory used?
|
|---|
| 461 | JE SHORT START_3 ; No -> skip
|
|---|
| 462 | CALL INIT_HIMEM ; Update high memory table
|
|---|
| 463 | CALL A20_ON ; Enable address line A20
|
|---|
| 464 | CALL CHECK_A20 ; Check if A20 is working
|
|---|
| 465 | STI ; CHECK_A20 disables interrupts
|
|---|
| 466 | OR AX, AX ; Bad news?
|
|---|
| 467 | JNE SHORT START_3 ; No - > skip
|
|---|
| 468 | LEA DX, $NO_A20 ; Cannot enable A20
|
|---|
| 469 | CALL RTEXT
|
|---|
| 470 | MOV AL, 0FFH
|
|---|
| 471 | JMP SHORT EXIT
|
|---|
| 472 | START_3: CALL INIT_FILEIO ; Initialize file handles
|
|---|
| 473 | CALL INIT_INT ; Initialize interrupts
|
|---|
| 474 | CALL INIT_TIMER ; Initialize timer interrupt
|
|---|
| 475 |
|
|---|
| 476 | CMP VCPI_FLAG, FALSE
|
|---|
| 477 | JNE START_VCPI
|
|---|
| 478 | LGDT GDT_PTR
|
|---|
| 479 | LIDT IDT_PTR
|
|---|
| 480 | MOV EAX, CR0
|
|---|
| 481 | OR AL, CR0_PE ; Enable protected mode
|
|---|
| 482 | MOV CR0, EAX
|
|---|
| 483 | JMP START_4 ; Flush prefetch queue
|
|---|
| 484 |
|
|---|
| 485 |
|
|---|
| 486 | ;
|
|---|
| 487 | ; Cleanup and exit to DOS
|
|---|
| 488 | ;
|
|---|
| 489 | ASSUME DS:NOTHING
|
|---|
| 490 | EXIT: PUSH AX
|
|---|
| 491 | CALL CLEANUP
|
|---|
| 492 | ASSUME DS:SV_DATA
|
|---|
| 493 | POP AX
|
|---|
| 494 | STI
|
|---|
| 495 | MOV AH, 4CH
|
|---|
| 496 | INT 21H
|
|---|
| 497 | JMP SHORT $ ; Never reached
|
|---|
| 498 |
|
|---|
| 499 |
|
|---|
| 500 | ;
|
|---|
| 501 | ; Convert some real-mode addresses to physical or linear addresses
|
|---|
| 502 | ;
|
|---|
| 503 | ASSUME DS:SV_DATA
|
|---|
| 504 | INIT_ADDR PROC NEAR
|
|---|
| 505 | LEA DI, GDT_LIN
|
|---|
| 506 | CALL INIT_LIN_1
|
|---|
| 507 | LEA DI, IDT_LIN
|
|---|
| 508 | CALL INIT_LIN_1
|
|---|
| 509 | LEA DI, V2P_GDTR
|
|---|
| 510 | CALL INIT_LIN_1
|
|---|
| 511 | LEA DI, V2P_IDTR
|
|---|
| 512 | CALL INIT_LIN_1
|
|---|
| 513 | LEA DI, V2P_LIN
|
|---|
| 514 | CALL INIT_LIN_1
|
|---|
| 515 | LEA DI, LOMEM_HEAD_PHYS
|
|---|
| 516 | CALL INIT_PHYS_1
|
|---|
| 517 | LEA DI, HIMEM_HEAD_PHYS
|
|---|
| 518 | CALL INIT_PHYS_1
|
|---|
| 519 | RET
|
|---|
| 520 | INIT_ADDR ENDP
|
|---|
| 521 |
|
|---|
| 522 | ;
|
|---|
| 523 | ; Convert one real-mode address to a physical address
|
|---|
| 524 | ;
|
|---|
| 525 | ; Note: the object pointed to by the address must be contained completely
|
|---|
| 526 | ; in *one* physical page.
|
|---|
| 527 | ;
|
|---|
| 528 | ; In: DI Pointer to a DWORD which contains in the lower word the
|
|---|
| 529 | ; real-mode offset
|
|---|
| 530 | ;
|
|---|
| 531 | INIT_PHYS_1 PROC NEAR
|
|---|
| 532 | MOV DX, [DI] ; Get real-mode offset
|
|---|
| 533 | MOV AX, SV_DATA ; Use this segment
|
|---|
| 534 | CALL RM_TO_PHYS ; Convert to physical address
|
|---|
| 535 | MOV [DI], EAX ; Store physical address
|
|---|
| 536 | RET
|
|---|
| 537 | INIT_PHYS_1 ENDP
|
|---|
| 538 |
|
|---|
| 539 | ;
|
|---|
| 540 | ; Convert one real-mode address to a linear address
|
|---|
| 541 | ;
|
|---|
| 542 | ; Note: the object pointed to by the address must not be accessed with
|
|---|
| 543 | ; G_PHYS_SEL. (Why?)
|
|---|
| 544 | ;
|
|---|
| 545 | ; In: DI Pointer to a DWORD which contains in the lower word the
|
|---|
| 546 | ; real-mode offset
|
|---|
| 547 | ;
|
|---|
| 548 | INIT_LIN_1 PROC NEAR
|
|---|
| 549 | XOR EAX, EAX
|
|---|
| 550 | MOV AX, SV_DATA ; Use this segment
|
|---|
| 551 | SHL EAX, 4
|
|---|
| 552 | MOVZX EDX, WORD PTR [DI] ; Get real-mode offset
|
|---|
| 553 | ADD EAX, EDX
|
|---|
| 554 | MOV [DI], EAX ; Store linear address
|
|---|
| 555 | RET
|
|---|
| 556 | INIT_LIN_1 ENDP
|
|---|
| 557 |
|
|---|
| 558 |
|
|---|
| 559 | ;
|
|---|
| 560 | ; Put the base addresses of some segments into the GDT. This is done
|
|---|
| 561 | ; by using the BASE_TABLE table. Each table entry consists of two (16-bit)
|
|---|
| 562 | ; words: The first word is the real-mode segment, the second word points
|
|---|
| 563 | ; to the GDT entry, which already contains the offset in the base 0..15 field.
|
|---|
| 564 | ;
|
|---|
| 565 |
|
|---|
| 566 | ASSUME DS:SV_DATA
|
|---|
| 567 | INIT_BASES PROC NEAR
|
|---|
| 568 | LEA SI, BASE_TABLE ; Table of segment/offset pairs
|
|---|
| 569 | IB_LOOP: MOV AX, [SI+0] ; Get real-mode segment
|
|---|
| 570 | OR AX, AX ; End of table?
|
|---|
| 571 | JZ SHORT IB_END ; Yes -> done
|
|---|
| 572 | MOV DI, [SI+2] ; Offset of GDT entry (SV_DATA)
|
|---|
| 573 | CALL INIT_DESC ; Set base field
|
|---|
| 574 | ADD SI, 4 ; Next table entry
|
|---|
| 575 | JMP SHORT IB_LOOP ; Repeat for all entries
|
|---|
| 576 | IB_END: RET ; Done
|
|---|
| 577 | INIT_BASES ENDP
|
|---|
| 578 |
|
|---|
| 579 |
|
|---|
| 580 | ;
|
|---|
| 581 | ; If called by emxl.exe, the command line is formatted this way:
|
|---|
| 582 | ;
|
|---|
| 583 | ; -/xxxx/
|
|---|
| 584 | ;
|
|---|
| 585 | ; where xxxx is the (hexadecimal) PSP segment of emxl.exe. Note that there
|
|---|
| 586 | ; is no blank before the dash. If called by emxl.exe, we used the (patched)
|
|---|
| 587 | ; options and the command line arguments of emxl.exe -- under DOS we can
|
|---|
| 588 | ; access memory of other `processes'.
|
|---|
| 589 | ;
|
|---|
| 590 |
|
|---|
| 591 | ASSUME DS:SV_DATA
|
|---|
| 592 | CHECK_EMXL PROC NEAR
|
|---|
| 593 | MOV ES, EMX_PSP ; Access PSP (command line)
|
|---|
| 594 | MOV DI, 80H ; Point to length field
|
|---|
| 595 | MOV AL, 7 ; Length must be 7
|
|---|
| 596 | SCAS BYTE PTR ES:[DI]
|
|---|
| 597 | JNE SHORT CE_RET
|
|---|
| 598 | MOV AL, "-" ; Check for "-/"
|
|---|
| 599 | SCAS BYTE PTR ES:[DI]
|
|---|
| 600 | JNE SHORT CE_RET
|
|---|
| 601 | MOV AL, "/"
|
|---|
| 602 | SCAS BYTE PTR ES:[DI]
|
|---|
| 603 | JNE SHORT CE_RET
|
|---|
| 604 | MOV DX, 0
|
|---|
| 605 | MOV CX, 0404H
|
|---|
| 606 | CE_1: MOV AL, ES:[DI]
|
|---|
| 607 | INC DI
|
|---|
| 608 | SUB AL, "0"
|
|---|
| 609 | JB SHORT CE_RET
|
|---|
| 610 | CMP AL, 10
|
|---|
| 611 | JB SHORT CE_2
|
|---|
| 612 | SUB AL, "A" - ("0" + 10)
|
|---|
| 613 | CMP AL, 10
|
|---|
| 614 | JB SHORT CE_RET
|
|---|
| 615 | CMP AL, 15
|
|---|
| 616 | JA SHORT CE_RET
|
|---|
| 617 | CE_2: SHL DX, CL
|
|---|
| 618 | OR DL, AL
|
|---|
| 619 | DEC CH
|
|---|
| 620 | JNZ SHORT CE_1
|
|---|
| 621 | MOV AL, "/" ; Check for "/", CR
|
|---|
| 622 | SCAS BYTE PTR ES:[DI]
|
|---|
| 623 | JNE SHORT CE_RET
|
|---|
| 624 | MOV AL, CR
|
|---|
| 625 | SCAS BYTE PTR ES:[DI]
|
|---|
| 626 | JNE SHORT CE_RET
|
|---|
| 627 | ;
|
|---|
| 628 | ; Check for emx signature
|
|---|
| 629 | ;
|
|---|
| 630 | MOV DI, 100H ; Data segment of emxl
|
|---|
| 631 | PUSH DS ; Save DS
|
|---|
| 632 | MOV AX, HDR_SEG
|
|---|
| 633 | MOV DS, AX
|
|---|
| 634 | ASSUME DS:NOTHING
|
|---|
| 635 | LEA SI, PATCH.BND_SIGNATURE
|
|---|
| 636 | MOV CX, HDR_EMX_LEN
|
|---|
| 637 | CLD
|
|---|
| 638 | REPE CMPS BYTE PTR DS:[SI], BYTE PTR ES:[DI]
|
|---|
| 639 | POP DS ; Restore DS
|
|---|
| 640 | ASSUME DS:SV_DATA
|
|---|
| 641 | JNE SHORT CE_RET
|
|---|
| 642 | MOV EMXL_SEG, DX ; It looks right
|
|---|
| 643 | CE_RET: RET
|
|---|
| 644 | CHECK_EMXL ENDP
|
|---|
| 645 |
|
|---|
| 646 | ;
|
|---|
| 647 | ; Parse EMXOPT and command line
|
|---|
| 648 | ;
|
|---|
| 649 | ; When run manually (or by an old version of emxl), process the following
|
|---|
| 650 | ; items (note that we don't know about the emxbind patch area here):
|
|---|
| 651 | ;
|
|---|
| 652 | ; 1/ EMXOPT environment variable
|
|---|
| 653 | ; 2/ command line
|
|---|
| 654 |
|
|---|
| 655 | ; When run by emxl.exe, process the following items:
|
|---|
| 656 | ;
|
|---|
| 657 | ; 1/ emxbind patch area of emxl.exe
|
|---|
| 658 | ; 2/ EMXOPT environment variable
|
|---|
| 659 | ; 3/ command line of emxl.exe
|
|---|
| 660 | ;
|
|---|
| 661 | ; When bound with an a.out file (without emxl.exe), process the following
|
|---|
| 662 | ; items:
|
|---|
| 663 | ;
|
|---|
| 664 | ; 1/ emxbind patch area of this program
|
|---|
| 665 | ; 2/ EMXOPT environment variable
|
|---|
| 666 | ;
|
|---|
| 667 | ASSUME DS:SV_DATA
|
|---|
| 668 |
|
|---|
| 669 | ARGS PROC NEAR
|
|---|
| 670 | MOV NP1.NP_ARG_COUNT, 0 ; No arguments
|
|---|
| 671 | MOV AX, EMXL_SEG
|
|---|
| 672 | OR AX, AX
|
|---|
| 673 | JNZ SHORT ARGS_01
|
|---|
| 674 | CMP BIND_FLAG, FALSE ; Bound?
|
|---|
| 675 | JE SHORT ARGS_10 ; No -> skip
|
|---|
| 676 | MOV AX, HDR_SEG
|
|---|
| 677 | LEA SI, PATCH.BND_OPTIONS
|
|---|
| 678 | JMP SHORT ARGS_02
|
|---|
| 679 | ARGS_01: LEA SI, (BIND_HEADER PTR ES:[100H]).BND_OPTIONS
|
|---|
| 680 | ARGS_02: MOV ES, AX
|
|---|
| 681 | CALL RM_OPTIONS ; Parse options in patch area
|
|---|
| 682 | CALL RM_SKIP_BLANKS
|
|---|
| 683 | OR AL, AL ; End of string?
|
|---|
| 684 | JNZ USAGE ; No -> error
|
|---|
| 685 | ;
|
|---|
| 686 | ; Process options in the EMXOPT environment variable
|
|---|
| 687 | ;
|
|---|
| 688 | ARGS_10: LEA BX, $EMXOPT
|
|---|
| 689 | CALL GETENV ; Get EMXOPT environment var.
|
|---|
| 690 | OR DI, DI ; Found?
|
|---|
| 691 | JZ SHORT ARGS_11 ; No -> skip
|
|---|
| 692 | MOV SI, DI
|
|---|
| 693 | CALL RM_OPTIONS ; Parse options in EMXOPT
|
|---|
| 694 | CALL RM_SKIP_BLANKS
|
|---|
| 695 | OR AL, AL ; End of string?
|
|---|
| 696 | JNZ USAGE ; No -> error
|
|---|
| 697 | ;
|
|---|
| 698 | ; Process command line
|
|---|
| 699 | ;
|
|---|
| 700 | ARGS_11: MOV AX, EMXL_SEG ; Try emxl's PSP
|
|---|
| 701 | OR AX, AX ; Run by emxl.exe?
|
|---|
| 702 | JNZ SHORT ARGS_12 ; Yes -> use emxl's cmd line
|
|---|
| 703 | MOV AX, EMX_PSP ; Use our PSP
|
|---|
| 704 | ARGS_12: MOV ES, AX ; Access PSP (command line)
|
|---|
| 705 | MOV SI, 81H ; Start of command line
|
|---|
| 706 | MOV BL, ES:[SI-1] ; Fetch length of command line
|
|---|
| 707 | MOV BH, 0
|
|---|
| 708 | MOV BYTE PTR ES:[SI+BX], 0 ; Terminate string with 0
|
|---|
| 709 | CALL RM_SKIP_BLANKS ; Skip leading blanks
|
|---|
| 710 | CMP BIND_FLAG, FALSE ; Bound?
|
|---|
| 711 | JNE SHORT ARGS_13 ; Yes -> don't read options
|
|---|
| 712 | CMP EMXL_SEG, 0 ; Run by new emxl?
|
|---|
| 713 | JNE SHORT ARGS_13 ; Yes -> don't read options
|
|---|
| 714 | PUSH SI
|
|---|
| 715 | CALL RM_OPTIONS ; Parse options
|
|---|
| 716 | POP AX
|
|---|
| 717 | PUSH SI ; Save pointer
|
|---|
| 718 | MOV CX, SI ; Copy options
|
|---|
| 719 | SUB CX, AX
|
|---|
| 720 | CMP CX, SIZE CMDL_OPTIONS
|
|---|
| 721 | JAE USAGE
|
|---|
| 722 | XCHG_DS_ES
|
|---|
| 723 | ASSUME DS:NOTHING
|
|---|
| 724 | MOV SI, AX
|
|---|
| 725 | LEA DI, CMDL_OPTIONS
|
|---|
| 726 | CLD
|
|---|
| 727 | REP MOVSB
|
|---|
| 728 | XOR AL, AL
|
|---|
| 729 | STOSB
|
|---|
| 730 | XCHG_DS_ES
|
|---|
| 731 | ASSUME DS:SV_DATA
|
|---|
| 732 | POP SI ; Restore pointer
|
|---|
| 733 | ARGS_13: CALL NAMES ; Parse arguments
|
|---|
| 734 | RET
|
|---|
| 735 | ARGS ENDP
|
|---|
| 736 |
|
|---|
| 737 |
|
|---|
| 738 | ;
|
|---|
| 739 | ; Parse command line for user program
|
|---|
| 740 | ;
|
|---|
| 741 | ; In: ES:SI Pointer to command line (null terminated)
|
|---|
| 742 | ;
|
|---|
| 743 | NAMES PROC NEAR
|
|---|
| 744 | XOR EDI, EDI
|
|---|
| 745 | LEA DI, ARG_STRINGS ; Put arguments here
|
|---|
| 746 | MOV NP1.NP_ARG_OFF, EDI
|
|---|
| 747 | MOV NP1.NP_ARG_SEL, G_SV_DATA_SEL
|
|---|
| 748 | CMP EMXL_SEG, 0 ; Run by emxl?
|
|---|
| 749 | JNE SHORT NAMES0 ; Yes -> copy argv[0]
|
|---|
| 750 | CMP BIND_FLAG, FALSE ; Bound?
|
|---|
| 751 | JE SHORT NAMES1 ; No -> skip
|
|---|
| 752 | ;
|
|---|
| 753 | ; Copy argv[0]
|
|---|
| 754 | ;
|
|---|
| 755 | NAMES0: MOV FS, ENV_SEG
|
|---|
| 756 | MOV BX, NP1.NP_ENV_SIZE ; End of environment
|
|---|
| 757 | ADD BX, 2 ; Skip word count
|
|---|
| 758 | MOV BYTE PTR [DI], 80H ; No flags set
|
|---|
| 759 | INC DI ; Skip flags byte
|
|---|
| 760 | COPY_ARGV0: MOV AL, FS:[BX] ; Copy program name
|
|---|
| 761 | MOV DS:[DI], AL
|
|---|
| 762 | INC BX
|
|---|
| 763 | INC DI
|
|---|
| 764 | OR AL, AL ; End of program name?
|
|---|
| 765 | JNZ COPY_ARGV0 ; No -> carry on copying
|
|---|
| 766 | INC NP1.NP_ARG_COUNT ; One argument
|
|---|
| 767 | ;
|
|---|
| 768 | ; Command line
|
|---|
| 769 | ;
|
|---|
| 770 | NAMES1: CALL RM_SKIP_BLANKS ; Skip blanks
|
|---|
| 771 | OR AL, AL ; End of command line?
|
|---|
| 772 | JZ SHORT NAMES9 ; Yes -> done
|
|---|
| 773 | ;
|
|---|
| 774 | ; Parse one argument
|
|---|
| 775 | ;
|
|---|
| 776 | ; "..." Quoted string, may contain blanks
|
|---|
| 777 | ; \" Odd number 2n+1 of \ followed by " is read as
|
|---|
| 778 | ; n backslashes followed by "
|
|---|
| 779 | ; \\" Even number 2n of \ followed by " is read as
|
|---|
| 780 | ; n backslashes followed by start/end of string
|
|---|
| 781 | ;
|
|---|
| 782 | NAMES2: MOV CX, 0 ; Number of backslashes := 0
|
|---|
| 783 | MOV DL, 0 ; Not within quoted string
|
|---|
| 784 | MOV DH, 00H ; No quotes used
|
|---|
| 785 | INC NP1.NP_ARG_COUNT ; We've found an argument
|
|---|
| 786 | MOV BX, DI ; Save pointer to flags
|
|---|
| 787 | INC DI ; Space for flags
|
|---|
| 788 | NAMES3: MOV AL, ES:[SI] ; Fetch character
|
|---|
| 789 | ;
|
|---|
| 790 | ; First test for characters which don't automatically insert backslashes
|
|---|
| 791 | ;
|
|---|
| 792 | CMP AL, "\" ; Backslash?
|
|---|
| 793 | JE SHORT NAMES_BACKSLASH ; Yes -> special treatment
|
|---|
| 794 | CMP AL, '"' ; Quote?
|
|---|
| 795 | JE SHORT NAMES_QUOTE ; Yes -> special treatment
|
|---|
| 796 | JCXZ NAMES5
|
|---|
| 797 | NAMES4: MOV BYTE PTR DS:[DI], "\"
|
|---|
| 798 | INC DI
|
|---|
| 799 | LOOP NAMES4
|
|---|
| 800 | NAMES5: OR AL, AL ; End of command line?
|
|---|
| 801 | JZ SHORT NAMES_END ; Yes -> special treatment
|
|---|
| 802 | CMP AL, " " ; Blank?
|
|---|
| 803 | JE SHORT NAMES_WHITE ; Yes -> special treatment
|
|---|
| 804 | CMP AL, TAB ; Tab?
|
|---|
| 805 | JE SHORT NAMES_WHITE ; Yes -> special treatment
|
|---|
| 806 | NAMES_PUT: MOV DS:[DI], AL ; Store character
|
|---|
| 807 | INC DI ; Next destination location
|
|---|
| 808 | INC SI ; Skip to next character
|
|---|
| 809 | JMP SHORT NAMES3 ; Repeat
|
|---|
| 810 |
|
|---|
| 811 | NAMES_BACKSLASH:INC CX ; Count backslashes
|
|---|
| 812 | INC SI ; Skip to next character
|
|---|
| 813 | JMP SHORT NAMES3 ; Repeat
|
|---|
| 814 |
|
|---|
| 815 | NAMES_WHITE: OR DL, DL ; Within string?
|
|---|
| 816 | JNZ SHORT NAMES_PUT ; Yes -> store character
|
|---|
| 817 | NAMES_END: OR DH, 80H ; Store flags (non-zero,
|
|---|
| 818 | MOV DS:[BX], DH ; otherwise end of string!)
|
|---|
| 819 | MOV BYTE PTR DS:[DI], 0 ; End of argument
|
|---|
| 820 | INC DI ; Next destination location
|
|---|
| 821 | JMP SHORT NAMES1 ; Skip blanks, check for end
|
|---|
| 822 |
|
|---|
| 823 | NAMES_QUOTE: SUB CX, 2 ; Insert CX/2 backslashes
|
|---|
| 824 | JB SHORT NAMES_Q1
|
|---|
| 825 | MOV BYTE PTR DS:[DI], "\"
|
|---|
| 826 | INC DI
|
|---|
| 827 | JMP SHORT NAMES_QUOTE
|
|---|
| 828 |
|
|---|
| 829 | NAMES_Q1: TEST CX, 1 ; Odd CX?
|
|---|
| 830 | MOV CX, 0
|
|---|
| 831 | JNZ SHORT NAMES_PUT ; Yes -> store quote
|
|---|
| 832 | OR DH, 01H ; Quotes used
|
|---|
| 833 | NOT DL ; Toggle quote flag
|
|---|
| 834 | INC SI ; Skip to next character
|
|---|
| 835 | JMP SHORT NAMES3 ; Repeat
|
|---|
| 836 |
|
|---|
| 837 | NAMES9: SUB DI, OFFSET SV_DATA:ARG_STRINGS
|
|---|
| 838 | MOV NP1.NP_ARG_SIZE, DI
|
|---|
| 839 | CMP NP1.NP_ARG_COUNT, 1 ; Program name given?
|
|---|
| 840 | JB USAGE ; No -> complain
|
|---|
| 841 | RET
|
|---|
| 842 |
|
|---|
| 843 | NAMES ENDP
|
|---|
| 844 |
|
|---|
| 845 | ;
|
|---|
| 846 | ; Read the environment, compute the size and number of variables
|
|---|
| 847 | ;
|
|---|
| 848 | ; We use emxl's environment if we're run by emxl.exe. This way, we
|
|---|
| 849 | ; get the executable path name of the program bound with emxl.
|
|---|
| 850 | ;
|
|---|
| 851 | ;
|
|---|
| 852 | ENVIRONMENT PROC NEAR
|
|---|
| 853 | MOV AX, EMXL_SEG ; Get emxl's PSP segment
|
|---|
| 854 | OR AX, AX ; Run by emxl.exe?
|
|---|
| 855 | JNZ SHORT ENV_1 ; Yes -> use emxl's environment
|
|---|
| 856 | MOV AX, EMX_PSP ; No: use our environment
|
|---|
| 857 | ENV_1: MOV ES, AX
|
|---|
| 858 | MOV BX, ES:[2CH] ; Get segment of environment
|
|---|
| 859 | MOV ENV_SEG, BX
|
|---|
| 860 | MOV ES, BX
|
|---|
| 861 | MOV NP1.NP_ENV_OFF, 0
|
|---|
| 862 | MOV NP1.NP_ENV_SEL, G_ENV_SEL
|
|---|
| 863 | MOV NP1.NP_ENV_SIZE, 0
|
|---|
| 864 | MOV NP1.NP_ENV_COUNT, 0
|
|---|
| 865 | MOV ENV_TOTAL_SIZE, 0
|
|---|
| 866 | CALL SCAN_ENV
|
|---|
| 867 | MOV NP1.NP_ENV_SIZE, BX
|
|---|
| 868 | MOV NP1.NP_ENV_COUNT, DX
|
|---|
| 869 | MOV ENV_TOTAL_SIZE, DI
|
|---|
| 870 | ;
|
|---|
| 871 | ; Build EMX_DIR which is the path name of the directory from which
|
|---|
| 872 | ; emx.exe was run or loaded. If emx.exe was bound to the program,
|
|---|
| 873 | ; EMX_DIR will be empty.
|
|---|
| 874 | ;
|
|---|
| 875 | CMP BIND_FLAG, FALSE ; Bound?
|
|---|
| 876 | JE SHORT EMXDIR_1 ; No -> scan environment
|
|---|
| 877 | CMP EMXL_SEG, 0 ; Run by emxl.exe?
|
|---|
| 878 | JZ SHORT EMXDIR_FAIL ; No -> EMX_DIR empty
|
|---|
| 879 | EMXDIR_1: MOV ES, EMX_PSP
|
|---|
| 880 | MOV ES, ES:[2CH] ; Get segment of environment
|
|---|
| 881 | CALL SCAN_ENV
|
|---|
| 882 | TEST BX, BX
|
|---|
| 883 | JZ SHORT EMXDIR_FAIL
|
|---|
| 884 | ;
|
|---|
| 885 | ; Find the length of the directory name
|
|---|
| 886 | ;
|
|---|
| 887 | ADD BX, 2 ; Skip word count
|
|---|
| 888 | MOV SI, BX ; Save start address
|
|---|
| 889 | MOV CX, BX ; Points to last delim + 1
|
|---|
| 890 | EMXDIR_LOOP: MOV AL, ES:[BX] ; Fetch next character
|
|---|
| 891 | TEST AL, AL ; End of string?
|
|---|
| 892 | JZ SHORT EMXDIR_EOS ; Yes -> done
|
|---|
| 893 | CMP AL, ":" ; Delimiter?
|
|---|
| 894 | JE SHORT EMXDIR_DELIM ; Yes -> remember position
|
|---|
| 895 | CMP AL, "\" ; Delimiter?
|
|---|
| 896 | JE SHORT EMXDIR_DELIM ; Yes -> remember position
|
|---|
| 897 | CMP AL, "/" ; Delimiter? (Can this happen?)
|
|---|
| 898 | JE SHORT EMXDIR_DELIM ; Yes -> remember position
|
|---|
| 899 | INC BX ; Skip the character
|
|---|
| 900 | JMP SHORT EMXDIR_LOOP ; Loop again
|
|---|
| 901 |
|
|---|
| 902 | EMXDIR_DELIM: INC BX ; Skip the character
|
|---|
| 903 | MOV CX, BX ; Remember position
|
|---|
| 904 | JMP SHORT EMXDIR_LOOP ; Loop again
|
|---|
| 905 |
|
|---|
| 906 | EMXDIR_EOS: SUB CX, SI ; Is there a directory?
|
|---|
| 907 | JZ EMXDIR_CWD ; No -> use current directory
|
|---|
| 908 | ;
|
|---|
| 909 | ; The program name includes a directory. For simplicity, assume
|
|---|
| 910 | ; it's an absolute path name.
|
|---|
| 911 | ;
|
|---|
| 912 | LEA DI, EMX_DIR
|
|---|
| 913 | EMXDIR_COPY: MOV AL, ES:[SI]
|
|---|
| 914 | MOV [DI], AL
|
|---|
| 915 | INC SI
|
|---|
| 916 | INC DI
|
|---|
| 917 | LOOP EMXDIR_COPY
|
|---|
| 918 | MOV BYTE PTR [DI], 0
|
|---|
| 919 | JMP SHORT EMXDIR_DONE
|
|---|
| 920 |
|
|---|
| 921 | ;
|
|---|
| 922 | ; The program name does not include a directory. Use the current
|
|---|
| 923 | ; directory.
|
|---|
| 924 | ;
|
|---|
| 925 | EMXDIR_CWD: MOV AH, 19H ; Get current disk
|
|---|
| 926 | INT 21H
|
|---|
| 927 | ADD AL, "A"
|
|---|
| 928 | MOV EMX_DIR[0], AL
|
|---|
| 929 | MOV EMX_DIR[1], ":"
|
|---|
| 930 | MOV EMX_DIR[2], "\"
|
|---|
| 931 | LEA SI, EMX_DIR + 3
|
|---|
| 932 | MOV DL, 0 ; Current drive
|
|---|
| 933 | MOV AH, 47H ; Get current directory
|
|---|
| 934 | INT 21H
|
|---|
| 935 | JC SHORT EMXDIR_FAIL
|
|---|
| 936 | ;
|
|---|
| 937 | ; Add a backslash to the end if required
|
|---|
| 938 | ;
|
|---|
| 939 | LEA SI, EMX_DIR + 2
|
|---|
| 940 | EMXDIR_BS: LODS BYTE PTR DS:[SI]
|
|---|
| 941 | TEST AL, AL
|
|---|
| 942 | JNZ SHORT EMXDIR_BS
|
|---|
| 943 | CMP BYTE PTR [SI-2], "\"
|
|---|
| 944 | JE SHORT EMXDIR_DONE
|
|---|
| 945 | MOV BYTE PTR [SI-1], "\"
|
|---|
| 946 | MOV BYTE PTR [SI-0], 0
|
|---|
| 947 | JMP SHORT EMXDIR_DONE
|
|---|
| 948 |
|
|---|
| 949 | EMXDIR_FAIL: MOV EMX_DIR[0], 0
|
|---|
| 950 | EMXDIR_DONE: RET
|
|---|
| 951 | ENVIRONMENT ENDP
|
|---|
| 952 |
|
|---|
| 953 |
|
|---|
| 954 | ;
|
|---|
| 955 | ; In: ES Segment of environment
|
|---|
| 956 | ;
|
|---|
| 957 | ; Out: DX Number of environment variables
|
|---|
| 958 | ; BX Pointer to end of environment
|
|---|
| 959 | ; DI Pointer to end of program name
|
|---|
| 960 | ;
|
|---|
| 961 | SCAN_ENV PROC NEAR
|
|---|
| 962 | MOV CX, 8000H
|
|---|
| 963 | XOR DX, DX
|
|---|
| 964 | XOR DI, DI
|
|---|
| 965 | XOR AL, AL
|
|---|
| 966 | CLD
|
|---|
| 967 | CMP WORD PTR ES:[DI], 0
|
|---|
| 968 | JE SHORT SE_2
|
|---|
| 969 | SE_1: INC DX
|
|---|
| 970 | REPNE SCAS BYTE PTR ES:[DI]
|
|---|
| 971 | JNE SHORT SE_9
|
|---|
| 972 | SCAS BYTE PTR ES:[DI]
|
|---|
| 973 | JE SHORT SE_3
|
|---|
| 974 | LOOP SE_1
|
|---|
| 975 | JMP SHORT SE_9
|
|---|
| 976 | SE_2: INC DI
|
|---|
| 977 | SE_3: MOV BX, DI
|
|---|
| 978 | ADD DI, 2 ; Skip word count
|
|---|
| 979 | REPNE SCAS BYTE PTR ES:[DI]
|
|---|
| 980 | JNE SHORT SE_9
|
|---|
| 981 | RET
|
|---|
| 982 | ;
|
|---|
| 983 | ; Bad environment
|
|---|
| 984 | ;
|
|---|
| 985 | SE_9: XOR DX, DX
|
|---|
| 986 | XOR BX, BX
|
|---|
| 987 | XOR DI, DI
|
|---|
| 988 | RET
|
|---|
| 989 | SCAN_ENV ENDP
|
|---|
| 990 |
|
|---|
| 991 |
|
|---|
| 992 | ;
|
|---|
| 993 | ; Get PATH and EMXPATH environment variables
|
|---|
| 994 | ;
|
|---|
| 995 | GET_PATH PROC NEAR
|
|---|
| 996 | LEA BX, $PATH
|
|---|
| 997 | CALL GETENV
|
|---|
| 998 | MOV ENV_PATH, DI
|
|---|
| 999 | LEA BX, $EMXPATH
|
|---|
| 1000 | CALL GETENV
|
|---|
| 1001 | MOV ENV_EMXPATH, DI
|
|---|
| 1002 | LEA BX, $EMXOPT
|
|---|
| 1003 | CALL GETENV
|
|---|
| 1004 | MOV ENV_EMXOPT, DI
|
|---|
| 1005 | RET
|
|---|
| 1006 | GET_PATH ENDP
|
|---|
| 1007 |
|
|---|
| 1008 | ;
|
|---|
| 1009 | ; Get EMXTMP environment variable. If EMXTMP is not set, TMP will
|
|---|
| 1010 | ; be used instead.
|
|---|
| 1011 | ;
|
|---|
| 1012 | GET_TMP PROC NEAR
|
|---|
| 1013 | LEA BX, $EMXTMP
|
|---|
| 1014 | CALL GETENV
|
|---|
| 1015 | OR DI, DI
|
|---|
| 1016 | JNZ SHORT GET_TMP1
|
|---|
| 1017 | LEA BX, $TMP
|
|---|
| 1018 | CALL GETENV
|
|---|
| 1019 | GET_TMP1: CALL SET_TMP_DIR
|
|---|
| 1020 | RET
|
|---|
| 1021 | GET_TMP ENDP
|
|---|
| 1022 |
|
|---|
| 1023 |
|
|---|
| 1024 | ;
|
|---|
| 1025 | ; Search environment
|
|---|
| 1026 | ;
|
|---|
| 1027 | ; In: DS:BX Pointer to name of environment variable
|
|---|
| 1028 | ;
|
|---|
| 1029 | ; Out: DI=0 Variable not found
|
|---|
| 1030 | ; ES:DI Pointer to value of environment variable
|
|---|
| 1031 | ;
|
|---|
| 1032 | GETENV PROC NEAR
|
|---|
| 1033 | MOV ES, ENV_SEG
|
|---|
| 1034 | XOR DI, DI ; ES:DI points to environment
|
|---|
| 1035 | CLD
|
|---|
| 1036 | GETENV_NEXT: CMP BYTE PTR ES:[DI], 0 ; Empty environment?
|
|---|
| 1037 | JE SHORT GETENV_FAILURE ; Yes -> not found
|
|---|
| 1038 | PUSH BX ; Save pointer to name
|
|---|
| 1039 | GETENV_COMPARE: MOV AL, [BX]
|
|---|
| 1040 | CMP AL, ES:[DI] ; Compare names
|
|---|
| 1041 | JNE SHORT GETENV_DIFF ; Mismatch -> try next one
|
|---|
| 1042 | OR AL, AL ; Shouldn't happen (`='!)
|
|---|
| 1043 | JZ SHORT GETENV_DIFF ; (name matches completely)
|
|---|
| 1044 | INC BX
|
|---|
| 1045 | INC DI
|
|---|
| 1046 | JMP SHORT GETENV_COMPARE ; Compare next character
|
|---|
| 1047 | GETENV_DIFF: POP BX ; Restore pointer to name
|
|---|
| 1048 | OR AL, AL ; End of name reached?
|
|---|
| 1049 | JE SHORT GETENV_EQUAL ; Yes -> candidate found
|
|---|
| 1050 | GETENV_SKIP: XOR AL, AL
|
|---|
| 1051 | MOV ECX, 32767 ; Search for next entry
|
|---|
| 1052 | REPNE SCAS BYTE PTR ES:[DI]
|
|---|
| 1053 | JMP SHORT GETENV_NEXT ; Check that entry
|
|---|
| 1054 |
|
|---|
| 1055 | GETENV_EQUAL: CMP BYTE PTR ES:[DI], "=" ; Exact match?
|
|---|
| 1056 | JNE SHORT GETENV_SKIP ; No -> go to next entry
|
|---|
| 1057 | INC DI ; Skip `='
|
|---|
| 1058 | JMP SHORT GETENV_RET ; Return pointer to value
|
|---|
| 1059 |
|
|---|
| 1060 | GETENV_FAILURE: XOR DI, DI ; Not found
|
|---|
| 1061 | GETENV_RET: RET
|
|---|
| 1062 | GETENV ENDP
|
|---|
| 1063 |
|
|---|
| 1064 |
|
|---|
| 1065 |
|
|---|
| 1066 |
|
|---|
| 1067 | ;
|
|---|
| 1068 | ; Read emxbind patch area
|
|---|
| 1069 | ;
|
|---|
| 1070 | ; Note: This code must use only 8086/88 instrutions
|
|---|
| 1071 | ;
|
|---|
| 1072 | ASSUME DS:SV_DATA
|
|---|
| 1073 | .8086
|
|---|
| 1074 | EMXBIND PROC NEAR
|
|---|
| 1075 | MOV AX, HDR_SEG
|
|---|
| 1076 | MOV ES, AX ; Access emxbind patch area
|
|---|
| 1077 | ASSUME ES:HDR_SEG
|
|---|
| 1078 | MOV AL, PATCH.BND_BIND_FLAG
|
|---|
| 1079 | MOV BIND_FLAG, AL ; Copy to data segment
|
|---|
| 1080 | EMXBIND_RET: RET
|
|---|
| 1081 | ASSUME ES:NOTHING
|
|---|
| 1082 | EMXBIND ENDP
|
|---|
| 1083 |
|
|---|
| 1084 | .386P
|
|---|
| 1085 |
|
|---|
| 1086 | ;
|
|---|
| 1087 | ; Abort if not running on a 386 or later
|
|---|
| 1088 | ;
|
|---|
| 1089 | ; Note: This code must use only 8086/88 instrutions
|
|---|
| 1090 | ;
|
|---|
| 1091 | ASSUME DS:SV_DATA
|
|---|
| 1092 | .8086
|
|---|
| 1093 | CHECK_CPU PROC NEAR
|
|---|
| 1094 | PUSHF ; Save flags
|
|---|
| 1095 | XOR AX, AX ; Clear all bits
|
|---|
| 1096 | PUSH AX ; Clear all flag bits
|
|---|
| 1097 | POPF
|
|---|
| 1098 | STI ; Enable interrupts
|
|---|
| 1099 | PUSHF ; Copy flags to AX
|
|---|
| 1100 | POP AX
|
|---|
| 1101 | POPF ; Restore flags
|
|---|
| 1102 | STI ; Enable interrupts
|
|---|
| 1103 | NOT AX ; Complement all bits
|
|---|
| 1104 | AND AX, 0F000H ; Flags!=F000 -> 286/386/...
|
|---|
| 1105 | JZ WRONG_CPU ; 86/186 -> error
|
|---|
| 1106 | PUSHF ; Save flags
|
|---|
| 1107 | MOV AX,7000H ; Set NT:=1, IOPL:=3
|
|---|
| 1108 | PUSH AX
|
|---|
| 1109 | POPF
|
|---|
| 1110 | STI ; Enable interrupts
|
|---|
| 1111 | PUSHF ; Copy flags to AX
|
|---|
| 1112 | POP AX
|
|---|
| 1113 | POPF ; Restore flags
|
|---|
| 1114 | STI ; Enable interrupts
|
|---|
| 1115 | AND AX, 7000H ; NT and IOPL sticky?
|
|---|
| 1116 | JZ WRONG_CPU ; No -> 286, error
|
|---|
| 1117 | RET ; Ok, it's an 80386
|
|---|
| 1118 |
|
|---|
| 1119 | WRONG_CPU: LEA DX, $WRONG_CPU ; Display message: 386 required
|
|---|
| 1120 | JMP SHORT ABORT ; and abort
|
|---|
| 1121 |
|
|---|
| 1122 | CHECK_CPU ENDP
|
|---|
| 1123 |
|
|---|
| 1124 | .386P
|
|---|
| 1125 |
|
|---|
| 1126 | ;
|
|---|
| 1127 | ; Abort if unsupported operating system
|
|---|
| 1128 | ;
|
|---|
| 1129 | ASSUME DS:SV_DATA
|
|---|
| 1130 | CHECK_OPSYS PROC NEAR
|
|---|
| 1131 | MOV AH, 30H
|
|---|
| 1132 | INT 21H ; Get operating system version
|
|---|
| 1133 | MOV DOS_MAJOR, AL
|
|---|
| 1134 | MOV DOS_MINOR, AH
|
|---|
| 1135 | CMP AL, 10 ; OS/2 1.x?
|
|---|
| 1136 | JE WRONG_OPSYS ; Yes -> won't work
|
|---|
| 1137 | CMP AL, 3 ; DOS 3.0 or later?
|
|---|
| 1138 | JAE OPSYS_OK ; Yes -> ok
|
|---|
| 1139 | CMP BIND_FLAG, FALSE ; Bound?
|
|---|
| 1140 | JE SHORT OPSYS_OK ; No -> ok
|
|---|
| 1141 | LEA DX, $DOS_VERSION ; Display error message
|
|---|
| 1142 | JMP SHORT ABORT ; and abort
|
|---|
| 1143 |
|
|---|
| 1144 | OPSYS_OK: RET
|
|---|
| 1145 |
|
|---|
| 1146 | WRONG_OPSYS: LEA DX, $WRONG_OPSYS ; Display error message
|
|---|
| 1147 | ABORT:: CALL RTEXT
|
|---|
| 1148 | MOV AX, 4CFFH ; Abort
|
|---|
| 1149 | INT 21H
|
|---|
| 1150 | JMP SHORT $ ; Never reached
|
|---|
| 1151 |
|
|---|
| 1152 | CHECK_OPSYS ENDP
|
|---|
| 1153 |
|
|---|
| 1154 |
|
|---|
| 1155 | ;
|
|---|
| 1156 | ; Check for DESQview
|
|---|
| 1157 | ;
|
|---|
| 1158 | ASSUME DS:SV_DATA
|
|---|
| 1159 | CHECK_DV PROC NEAR
|
|---|
| 1160 | MOV AH, 2BH ; `Set current date'
|
|---|
| 1161 | MOV AL, 01H ; Subfunction: get version
|
|---|
| 1162 | MOV CX, 4445H ; 'DE'
|
|---|
| 1163 | MOV DX, 5351H ; 'SQ'
|
|---|
| 1164 | INT 21H
|
|---|
| 1165 | CMP AL, 0FFH ; DESQview installed?
|
|---|
| 1166 | JE SHORT CDV_RET ; No -> return
|
|---|
| 1167 | MOV DV_FLAG, NOT FALSE
|
|---|
| 1168 | CDV_RET: RET
|
|---|
| 1169 | CHECK_DV ENDP
|
|---|
| 1170 |
|
|---|
| 1171 |
|
|---|
| 1172 | ;
|
|---|
| 1173 | ; Determine the linear address of video memory and set the
|
|---|
| 1174 | ; base address of G_VIDEO_SEL
|
|---|
| 1175 | ;
|
|---|
| 1176 | ; Must not be called before INIT_PAGING as G_PHYS_DESC is used!
|
|---|
| 1177 | ;
|
|---|
| 1178 | ASSUME DS:SV_DATA
|
|---|
| 1179 | INIT_VIDEO PROC NEAR
|
|---|
| 1180 | MOV EAX, 0B8000H ; ???
|
|---|
| 1181 | CMP MACHINE, MACH_PC98 ; NEC PC-98?
|
|---|
| 1182 | JE SHORT VIOMEM1 ; Yes ->
|
|---|
| 1183 | CMP MACHINE, MACH_FMR70 ; FMR70?
|
|---|
| 1184 | JE SHORT VIOMEM1 ; Yes ->
|
|---|
| 1185 | INT 11H ; Equipment determination
|
|---|
| 1186 | AND AL, 30H ; Initial video mode
|
|---|
| 1187 | CMP AL, 30H ; Monochrome adapter?
|
|---|
| 1188 | MOV EAX, 0B0000H
|
|---|
| 1189 | JE SHORT VIOMEM1 ; Yes ->
|
|---|
| 1190 | MOV EAX, 0B8000H
|
|---|
| 1191 | VIOMEM1: ADD EAX, G_PHYS_BASE ; Compute linear address
|
|---|
| 1192 | MOV VIDEO_LIN, EAX ; Store linear address
|
|---|
| 1193 | LEA DI, G_VIDEO_DESC
|
|---|
| 1194 | CALL RM_SEG_BASE
|
|---|
| 1195 | CALL VINIT ; Get the width and height
|
|---|
| 1196 | RET
|
|---|
| 1197 | INIT_VIDEO ENDP
|
|---|
| 1198 |
|
|---|
| 1199 | ;
|
|---|
| 1200 | ; Cleanup before returning to DOS
|
|---|
| 1201 | ;
|
|---|
| 1202 | ASSUME DS:NOTHING
|
|---|
| 1203 | CLEANUP PROC NEAR
|
|---|
| 1204 | MOV AX, SV_DATA
|
|---|
| 1205 | MOV DS, AX
|
|---|
| 1206 | ASSUME DS:SV_DATA
|
|---|
| 1207 | CALL CLEANUP_TIMER
|
|---|
| 1208 | CALL CLEANUP_INT
|
|---|
| 1209 | CALL CLEANUP_SIGNAL
|
|---|
| 1210 | CALL CLEANUP_SWAP
|
|---|
| 1211 | CALL CLEANUP_MEMORY
|
|---|
| 1212 | CALL CLEANUP_VCPI
|
|---|
| 1213 | CALL CLEANUP_XMS
|
|---|
| 1214 | CALL CLEANUP_A20
|
|---|
| 1215 | RET
|
|---|
| 1216 | CLEANUP ENDP
|
|---|
| 1217 |
|
|---|
| 1218 | ;
|
|---|
| 1219 | ; Out of memory (real mode)
|
|---|
| 1220 | ;
|
|---|
| 1221 | ASSUME DS:SV_DATA
|
|---|
| 1222 | RM_OUT_OF_MEM: LEA DX, $RM_OUT_OF_MEM
|
|---|
| 1223 | CALL RTEXT
|
|---|
| 1224 | MOV AL, 0FFH
|
|---|
| 1225 | JMP EXIT
|
|---|
| 1226 |
|
|---|
| 1227 |
|
|---|
| 1228 | INIT_CODE ENDS
|
|---|
| 1229 |
|
|---|
| 1230 | END START
|
|---|