source: vendor/emx/current/src/dos/emxl.asm

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

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 18.3 KB
Line 
1;
2; EMXL.ASM -- emx loader (emxl.exe)
3;
4; Copyright (c) 1991-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; <START_OF_EXCEPTION>
24; As a special exception, if you bind emxl.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 emxl.exe to an executable file, you
30; have to include source code for emxl.exe. When distributing
31; emxl.exe as separate file, the GPL applies without exceptions to
32; emxl.exe.
33;
34; If you modify this file, you have to replace the text between
35; the outer <START_OF_EXCEPTION> and <END_OF_EXCEPTION> markers with
36; the following paragraph (which currently does not apply as you have
37; not modified this file):
38;
39; As a special exception, if you bind emxl.exe to an executable file
40; (using emxbind), this does not cause the resulting executable file
41; to be covered by the GNU General Public License. The source code
42; for emxl.exe must be distributed with the executable file. This
43; exception does not however invalidate any other reasons why the
44; executable file might be covered by the GNU General Public License.
45; <END_OF_EXCEPTION>
46;
47
48 INCLUDE EMX.INC
49 INCLUDE HEADERS.INC
50 INCLUDE VERSION.INC
51
52 .8086
53
54;
55; Data (the name SV_DATA stems from emx, we're using EMX.INC!)
56;
57SV_DATA SEGMENT
58
59PSP_SEG WORD ? ; Program prefix segment
60ENV_SEG WORD ? ; Environment segment
61NAME_OFF WORD ? ; Offset of prog name (ENV_SEG)
62NAME_LEN WORD ? ; Length of prog name
63
64;
65; Parameter block for INT 21H, AX=4B00H
66;
67PAR_BLOCK WORD 0 ; Copy parent's environment
68 WORD OFFSET CMD_LINE ; Command line
69 WORD SEG CMD_LINE
70 WORD 5CH ; FCB1
71PB_SEG1 WORD ?
72 WORD 6CH ; FCB2
73PB_SEG2 WORD ?
74
75;
76; DPMI_FLAG is non-zero if a DPMI server has been found, but no
77; VCPI server
78;
79DPMI_FLAG BYTE FALSE ; Initially FALSE
80
81;
82; Messages
83;
84$EMX_NOT_FOUND BYTE "emx not found", CR, LF, "$"
85$RSX_NOT_FOUND BYTE "rsx not found, DPMI not supported by emx", CR, LF, "$"
86$USE_EMXBIND BYTE "Use emxbind", CR, LF, "$"
87$BAD_ENV BYTE "Bad environment", CR, LF, "$"
88
89;
90; Names of devices implemented by expanded memory managers
91;
92EMS_FNAME BYTE "EMMXXXX0", 0 ; EMS enabled
93NOEMS_FNAME1 BYTE "EMMQXXX0", 0 ; EMS disabled
94NOEMS_FNAME2 BYTE "$MMXXXX0",0 ; EMS disabled
95
96;
97; Names of environment variables
98;
99$EMX BYTE "EMX", 0
100$PATH BYTE "PATH", 0
101
102;
103; Name of emx.exe for searching in the current working directory and PATH
104;
105$EMX_EXE BYTE "emx.exe", 0
106EMX_EXE_LEN = THIS BYTE - $EMX_EXE ; Length of name, with 0
107
108;
109; This command line is passed to emx.exe
110;
111CMD_LINE BYTE 7 ; 7 bytes
112 BYTE "-/" ; Special marker
113CMD_LINE_PSP BYTE "0000" ; PSP_SEG, hexadecimal
114 BYTE "/" ; Another special marker
115 BYTE CR ; End of command line
116
117;
118; Build path name here when using directory from PATH environment variable
119;
120PGM_NAME BYTE 128 DUP (?)
121PGM_NAME_END LABEL BYTE
122
123SV_DATA ENDS
124
125
126;
127; This area will be patched by emxbind
128;
129HDR_SEG SEGMENT
130PATCH LABEL BIND_HEADER
131 BYTE "emx ", VERSION, 0
132 BYTE (SIZE BIND_HEADER - HDR_VERSION_LEN) DUP (0)
133HDR_SEG ENDS
134
135;
136; Code
137;
138INIT_CODE SEGMENT
139
140 ASSUME CS:INIT_CODE
141 ASSUME DS:NOTHING, ES:NOTHING
142
143;
144; Setup data segment. Note: This macro modifies AX.
145;
146SET_DS MACRO
147 MOV AX, SV_DATA
148 MOV DS, AX
149 ASSUME DS:SV_DATA
150 ENDM
151
152;
153; The program starts here
154;
155ENTRY: SET_DS ; Setup data segment
156 MOV PSP_SEG, ES ; Save program prefix segment
157 CALL INIT ; Initialize
158 CALL CHECK_DPMI ; Check for DPMI
159 CALL GET_NAME ; Get program name
160 CALL BIND_HDR ; Check patch area
161 CALL TRY_EMX_ENV ; Use EMX environment variable
162 CALL TRY_CWD ; Search current directory
163 CALL TRY_PATH ; Use PATH environment variable
164 LEA DX, $EMX_NOT_FOUND ; Give up
165 CMP DPMI_FLAG, FALSE
166 JE FAIL
167 LEA DX, $RSX_NOT_FOUND
168FAIL: JMP ABORT
169
170;
171; Initialization
172;
173INIT PROC NEAR
174 MOV AX, PSP_SEG
175 MOV PB_SEG1, AX ; Fill in parameter block
176 MOV PB_SEG2, AX ; for DOS function 4BH (EXEC)
177 MOV ES, AX
178 MOV AX, ES:[2CH] ; Get environment segment
179 MOV ENV_SEG, AX
180 LEA BX, CMD_LINE_PSP ; Insert PSP_SEG, hexadecimal
181 MOV CX, 0404H ; 4 digits, shift by 4 bits
182 MOV DX, PSP_SEG
183INIT_1: ROL DX, CL
184 MOV AL, DL
185 AND AL, 0FH
186 ADD AL, "0"
187 CMP AL, "9"
188 JBE INIT_2
189 ADD AL, "A" - ("0" + 10)
190INIT_2: MOV [BX], AL
191 INC BX
192 DEC CH
193 JNZ INIT_1
194 RET
195INIT ENDP
196
197
198;
199; Check for DPMI server
200;
201CHECK_DPMI PROC NEAR
202 MOV AX, 1687H ; Check for DPMI server
203 INT 2FH
204 OR AX, AX ; Server present?
205 JNZ DPMI_RET ; No -> call emx.exe
206 TEST BX, 1 ; 32-bit programs supported?
207 JZ DPMI_RET ; No -> hope we can get VCPI
208;
209; Now we have detected a DPMI server. Run rsx if we don't find a
210; VCPI server. First we have to check for an EMM.
211;
212; First, check the EMS interrupt vector
213;
214 MOV AX, 3567H ; Get interrupt vector 67H
215 INT 21H
216 MOV AX, ES
217 OR AX, BX ; Is the vector 0:0 ?
218 JZ NO_VCPI ; Yes -> no VCPI
219;
220; Check for an EMM with EMS enabled
221;
222 LEA DX, EMS_FNAME
223 CALL CHECK_EMM ; EMS present?
224 JC EMM_DISABLED ; No -> try disabled EMS
225;
226; Check EMM status
227;
228 MOV AH, 40H ; Get EMM status
229 INT 67H
230 CMP AH, 0 ; Successful?
231 JE EMM_OK ; Yes -> check VCPI
232 JMP NO_VCPI ; No VCPI
233
234;
235; Check for an EMM with EMS disabled (using undocumented "features")
236;
237EMM_DISABLED: LEA DX, NOEMS_FNAME1
238 CALL CHECK_EMM
239 JNC EMM_OK ; EMM present
240 LEA DX, NOEMS_FNAME2
241 CALL CHECK_EMM
242 JC NO_VCPI ; No EMM present -> no VCPI
243;
244; There is an EMM with EMS enabled or disabled. Check for VCPI
245;
246EMM_OK: MOV AX, 0DE00H ; VCPI presence detection
247 INT 67H
248 CMP AH, 0 ; VCPI present?
249 JE DPMI_RET ; Yes -> use emx
250;
251; Now we have found a DPMI server, but no VCPI server. We
252; should use rsx instead of emx
253;
254NO_VCPI: MOV DPMI_FLAG, NOT FALSE ; Set flag
255 MOV AX, "SR" ; First 2 letters of "RSX"
256 MOV WORD PTR $EMX, AX ; Patch name of env. variable
257 MOV AX, "sr" ; First 2 letters of "rsx.exe"
258 MOV WORD PTR $EMX_EXE, AX ; Patch name of executable
259DPMI_RET: RET
260CHECK_DPMI ENDP
261
262
263;
264; Check for the presence of an expanded memory manager (emx.exe
265; will perform more complete checks)
266;
267; In: DX Pointer to device name
268;
269; Out: NC EMM present
270;
271CHECK_EMM PROC NEAR
272 MOV AX, 3D00H ; Open
273 INT 21H
274 JC CE_RET
275;
276; A file or device with that name exists. Check for a device
277;
278 MOV BX, AX ; Handle
279 MOV AX, 4400H ; IOCTL: get device data
280 INT 21H
281 JC CE_FAIL ; Failure -> no EMM
282 TEST DL, 80H ; Device?
283 JZ CE_FAIL ; No -> no EMM
284 MOV AX, 4407H ; IOCTL: check output status
285 INT 21H
286 JC CE_FAIL ; Failure -> no EMM
287 CMP AL, 0FFH ; Ready?
288 JNE CE_FAIL ; No -> no EMM
289 MOV AH, 3EH ; Close
290 INT 21H
291 CLC
292CE_RET: RET
293
294CE_FAIL: MOV AH, 3EH ; Close
295 INT 21H
296 STC
297 RET
298CHECK_EMM ENDP
299
300
301;
302; Find program name
303;
304GET_NAME PROC NEAR
305 MOV ES, ENV_SEG ; Scan environment
306 XOR DI, DI ; starting at offset 0
307 MOV CX, 8000H ; Maximum environment size
308 XOR AL, AL ; Search for bytes of zeros
309 CLD ; Incrementing
310GET_NAME_1: REPNE SCAS BYTE PTR ES:[DI] ; Skip string
311 JNE GET_NAME_ERR ; Count exhausted -> error
312 SCAS BYTE PTR ES:[DI] ; End of environment?
313 JE GET_NAME_9 ; Yes -> program name found
314 LOOP GET_NAME_1 ; Next string, 1st char skipped
315GET_NAME_ERR: LEA DX, $BAD_ENV ; Bad environment
316 JMP ABORT
317
318GET_NAME_9: ADD DI, 2 ; Skip count
319 MOV NAME_OFF, DI ; Offset of program name
320 CALL STRLEN ; Compute length
321 MOV NAME_LEN, CX
322 RET
323GET_NAME ENDP
324
325
326;
327; Check emxbind patch area
328;
329BIND_HDR PROC NEAR
330 MOV AX, HDR_SEG
331 MOV ES, AX ; Access emxbind patch area
332 ASSUME ES:HDR_SEG
333 CMP PATCH.BND_BIND_FLAG, FALSE ; Bound?
334 JNE BIND_HDR_1 ; Yes -> continue
335 LEA DX, $USE_EMXBIND ; Must be bound to a.out
336 JMP ABORT
337BIND_HDR_1: RET
338BIND_HDR ENDP
339
340 ASSUME ES:NOTHING
341
342;
343; Display error message and abort program
344;
345; In: DX Offset of dollar-delimited error message in SV_DATA
346;
347ABORT: SET_DS ; This can't hurt
348 MOV AH, 09H ; Display string
349 INT 21H
350 MOV AX, 4C01H ; Terminate process, rc=1
351 INT 21H
352
353;
354; Try to find emx.exe using EMX environment variable
355;
356TRY_EMX_ENV PROC NEAR
357 LEA BX, $EMX
358 CALL GETENV
359 JC TRY_EMX_ENV_RET
360 MOV DX, DI
361 MOV_DS_ES
362 ASSUME DS:NOTHING
363 CALL SPAWN
364 ASSUME DS:SV_DATA
365TRY_EMX_ENV_RET:RET
366TRY_EMX_ENV ENDP
367
368;
369; Try to find emx.exe in current working directory
370;
371TRY_CWD PROC NEAR
372 LEA DX, $EMX_EXE
373 CALL SPAWN
374 RET
375TRY_CWD ENDP
376
377;
378; Try to find emx.exe in the directories listed in the PATH environment
379; variable
380;
381TRY_PATH PROC NEAR
382 LEA BX, $PATH
383 CALL GETENV
384 JC TRY_PATH_RET
385 MOV SI, DI
386FIND_2: LEA DI, PGM_NAME
387FIND_3: MOV AL, ES:[SI]
388 INC SI
389 OR AL, AL
390 JZ TRY_PATH_RET
391 CMP AL, " "
392 JE FIND_3
393 CMP AL, TAB
394 JE FIND_3
395 CMP AL, ";"
396 JE FIND_3
397FIND_4: CMP DI, OFFSET PGM_NAME_END
398 JAE FIND_5
399 MOV [DI], AL
400 MOV AH, AL
401 INC DI
402FIND_5: MOV AL, ES:[SI]
403 INC SI
404 OR AL, AL
405 JZ FIND_6
406 CMP AL, " "
407 JE FIND_5
408 CMP AL, TAB
409 JE FIND_5
410 CMP AL, ";"
411 JNE FIND_4
412FIND_6: DEC SI
413 CMP DI, OFFSET PGM_NAME_END - EMX_EXE_LEN
414 JAE FIND_2
415;
416; We don't support DBCS in emxl.exe: PATH should not contain directories
417; whose name ends with a DBCS characters whose 2nd byte is 2F, 3AH, or 5CH.
418;
419 CMP AH, "\"
420 JE FIND_7
421 CMP AH, "/"
422 JE FIND_7
423 CMP AH, ":"
424 JE FIND_7
425 CMP DI, OFFSET PGM_NAME_END
426 JAE FIND_7
427 MOV BYTE PTR DS:[DI], "\"
428 INC DI
429FIND_7: PUSH ES
430 PUSH SI
431 LEA SI, $EMX_EXE
432 MOV CX, EMX_EXE_LEN
433FIND_8: LODSB
434 MOV [DI], AL
435 INC DI
436 LOOP FIND_8
437 LEA DX, PGM_NAME
438 CALL SPAWN
439 POP SI
440 POP ES
441 JMP FIND_2
442
443TRY_PATH_RET: RET
444
445TRY_PATH ENDP
446
447
448
449;
450; Find environment entry
451;
452; In: BX Points to zero-terminated name of environment variable
453;
454; Out: CY Not found
455; NC Found
456; DI Points to value of environment variable
457;
458
459 ASSUME DS:SV_DATA
460
461GETENV PROC NEAR
462 MOV ES, ENV_SEG
463 XOR DI, DI
464 CLD
465GETENV_NEXT: CMP BYTE PTR ES:[DI], 0 ; Empty environment?
466 JE GETENV_FAILURE ; Yes -> not found
467 PUSH BX ; Save pointer to name
468GETENV_COMPARE: MOV AL, [BX]
469 CMP AL, ES:[DI] ; Compare names
470 JNE GETENV_DIFF ; Mismatch -> try next one
471 OR AL, AL ; Shouldn't happen (`='!)
472 JZ GETENV_DIFF ; (name matches completely)
473 INC BX
474 INC DI
475 JMP GETENV_COMPARE ; Compare next character
476GETENV_DIFF: POP BX ; Restore pointer to name
477 OR AL, AL ; End of name reached?
478 JE GETENV_EQUAL ; Yes -> candidate found
479GETENV_SKIP: XOR AL, AL
480 MOV CX, 32767 ; Search for next entry
481 REPNE SCAS BYTE PTR ES:[DI]
482 JMP GETENV_NEXT ; Check that entry
483
484GETENV_EQUAL: CMP BYTE PTR ES:[DI], "=" ; Exact match?
485 JNE GETENV_SKIP ; No -> go to next entry
486 INC DI ; Skip `='
487 CLC
488 JMP GETENV_RET ; Return pointer to value
489
490GETENV_FAILURE: STC ; Not found
491GETENV_RET: RET
492
493GETENV ENDP
494
495;
496; Compute the length of a zero-terminated string
497;
498; In: ES:SI Points to string
499;
500; Out: CX Length
501;
502STRLEN PROC NEAR
503 XOR CX, CX
504 XOR AL, AL
505STRLEN_1: SCASB
506 JE STRLEN_2
507 INC CX
508 JMP STRLEN_1
509STRLEN_2: RET
510STRLEN ENDP
511
512;
513; Try to run a program. Exit if successful, return if failed.
514;
515; In: DS:DX Points to path name of program
516;
517; Out: DS SV_DATA
518;
519
520 ASSUME DS:NOTHING
521
522SPAWN PROC NEAR
523 MOV AX, SV_DATA
524 MOV ES, AX
525 ASSUME ES:SV_DATA
526 LEA BX, PAR_BLOCK ; ES:BX -> parameter block
527 MOV AX, 4B00H ; Load and execute program
528 INT 21H
529 SET_DS ; Restore data segment
530 JNC DONE ; Success -> terminate
531 RET
532
533DONE: MOV AH, 4DH ; Get return code of child
534 INT 21H ; process
535 MOV AH, 4CH ; terminate process
536 INT 21H
537
538SPAWN ENDP
539
540 ASSUME ES:NOTHING
541
542
543INIT_CODE ENDS
544
545
546RM_STACK SEGMENT
547 WORD 256 DUP (?)
548RM_STACK ENDS
549
550 END ENTRY
Note: See TracBrowser for help on using the repository browser.