source: vendor/emx/current/src/dos/emx.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: 46.4 KB
Line 
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
81SV_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
97EMXL_SEG WORD 0 ; PSP segment of emxl
98EMX_PSP WORD ? ; Our PSP segment
99ENV_SEG WORD ? ; Environment segment
100ENV_PATH WORD ? ; Pointer to PATH value
101ENV_EMXPATH WORD ? ; Pointer to EMXPATH value
102ENV_EMXOPT WORD ? ; Pointer to EMXOPT value
103ENV_TOTAL_SIZE WORD ? ; Size of environment, w/ exe
104
105;
106; The arguments of the initial process
107;
108ARG_STRINGS BYTE 256 DUP (?) ; Arguments
109
110;
111; Floating point
112;
113FP_TMP WORD ? ; 287/387 CW or SW
114FP_FLAG BYTE FP_NO ; No coprocessor
115
116;
117; This field is copied from HDR_SEG to SV_DATA
118;
119BIND_FLAG BYTE ? ; Bound application
120
121;
122; DOS version
123;
124DOS_MAJOR BYTE ?
125DOS_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;
132CMDL_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
144SV_DATA ENDS
145
146
147;
148; This area will be patched by emxbind when using emx.exe as DOS stub.
149;
150HDR_SEG SEGMENT
151PATCH LABEL BIND_HEADER
152 BYTE "emx ", VERSION, 0
153 BYTE (SIZE BIND_HEADER - HDR_VERSION_LEN) DUP (0)
154HDR_SEG ENDS
155
156
157 .386P
158
159SV_CODE SEGMENT
160
161 ASSUME CS:SV_CODE, DS:NOTHING
162
163;
164; This is the proteced mode entry point
165;
166PROT1 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;
208PROT2: 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
251LOAD3: 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
266DISPATCH_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
279DISPATCH_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;
298DELAY_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
309INIT_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
354INIT_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
364IFP_EMU: OR EAX, CR0_TS OR CR0_EM ; Task switched, emulate
365IFP_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
369INIT_FP ENDP
370
371;
372; Initialize DBCS lead byte table. Note that we can't call GET_DBCS_LEAD
373; directly.
374;
375INIT_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
383INIT_DBCS ENDP
384
385SV_CODE ENDS
386
387
388SV_STACK SEGMENT
389 WORD 2048 DUP (?)
390SV_TOS LABEL WORD
391SV_STACK ENDS
392
393
394
395RM_STACK SEGMENT
396 WORD 1024 DUP (?)
397RM_TOS LABEL WORD
398RM_STACK ENDS
399
400
401INIT_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;
411START_4: JMPF16 G_SV_CODE_SEL, PROT1
412
413;
414; Entrypoint
415;
416
417 ASSUME DS:NOTHING
418 .8086
419START: 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
459START_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
472START_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
490EXIT: 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
504INIT_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
520INIT_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;
531INIT_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
537INIT_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;
548INIT_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
556INIT_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
567INIT_BASES PROC NEAR
568 LEA SI, BASE_TABLE ; Table of segment/offset pairs
569IB_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
576IB_END: RET ; Done
577INIT_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
592CHECK_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
606CE_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
617CE_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
643CE_RET: RET
644CHECK_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
669ARGS 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
679ARGS_01: LEA SI, (BIND_HEADER PTR ES:[100H]).BND_OPTIONS
680ARGS_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;
688ARGS_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;
700ARGS_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
704ARGS_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
733ARGS_13: CALL NAMES ; Parse arguments
734 RET
735ARGS ENDP
736
737
738;
739; Parse command line for user program
740;
741; In: ES:SI Pointer to command line (null terminated)
742;
743NAMES 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;
755NAMES0: 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
760COPY_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;
770NAMES1: 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;
782NAMES2: 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
788NAMES3: 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
797NAMES4: MOV BYTE PTR DS:[DI], "\"
798 INC DI
799 LOOP NAMES4
800NAMES5: 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
806NAMES_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
811NAMES_BACKSLASH:INC CX ; Count backslashes
812 INC SI ; Skip to next character
813 JMP SHORT NAMES3 ; Repeat
814
815NAMES_WHITE: OR DL, DL ; Within string?
816 JNZ SHORT NAMES_PUT ; Yes -> store character
817NAMES_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
823NAMES_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
829NAMES_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
837NAMES9: 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
843NAMES 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;
852ENVIRONMENT 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
857ENV_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
879EMXDIR_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
890EMXDIR_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
902EMXDIR_DELIM: INC BX ; Skip the character
903 MOV CX, BX ; Remember position
904 JMP SHORT EMXDIR_LOOP ; Loop again
905
906EMXDIR_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
913EMXDIR_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;
925EMXDIR_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
940EMXDIR_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
949EMXDIR_FAIL: MOV EMX_DIR[0], 0
950EMXDIR_DONE: RET
951ENVIRONMENT 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;
961SCAN_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
969SE_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
976SE_2: INC DI
977SE_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;
985SE_9: XOR DX, DX
986 XOR BX, BX
987 XOR DI, DI
988 RET
989SCAN_ENV ENDP
990
991
992;
993; Get PATH and EMXPATH environment variables
994;
995GET_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
1006GET_PATH ENDP
1007
1008;
1009; Get EMXTMP environment variable. If EMXTMP is not set, TMP will
1010; be used instead.
1011;
1012GET_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
1019GET_TMP1: CALL SET_TMP_DIR
1020 RET
1021GET_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;
1032GETENV PROC NEAR
1033 MOV ES, ENV_SEG
1034 XOR DI, DI ; ES:DI points to environment
1035 CLD
1036GETENV_NEXT: CMP BYTE PTR ES:[DI], 0 ; Empty environment?
1037 JE SHORT GETENV_FAILURE ; Yes -> not found
1038 PUSH BX ; Save pointer to name
1039GETENV_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
1047GETENV_DIFF: POP BX ; Restore pointer to name
1048 OR AL, AL ; End of name reached?
1049 JE SHORT GETENV_EQUAL ; Yes -> candidate found
1050GETENV_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
1055GETENV_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
1060GETENV_FAILURE: XOR DI, DI ; Not found
1061GETENV_RET: RET
1062GETENV 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
1074EMXBIND 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
1080EMXBIND_RET: RET
1081 ASSUME ES:NOTHING
1082EMXBIND 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
1093CHECK_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
1119WRONG_CPU: LEA DX, $WRONG_CPU ; Display message: 386 required
1120 JMP SHORT ABORT ; and abort
1121
1122CHECK_CPU ENDP
1123
1124 .386P
1125
1126;
1127; Abort if unsupported operating system
1128;
1129 ASSUME DS:SV_DATA
1130CHECK_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
1144OPSYS_OK: RET
1145
1146WRONG_OPSYS: LEA DX, $WRONG_OPSYS ; Display error message
1147ABORT:: CALL RTEXT
1148 MOV AX, 4CFFH ; Abort
1149 INT 21H
1150 JMP SHORT $ ; Never reached
1151
1152CHECK_OPSYS ENDP
1153
1154
1155;
1156; Check for DESQview
1157;
1158 ASSUME DS:SV_DATA
1159CHECK_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
1168CDV_RET: RET
1169CHECK_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
1179INIT_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
1191VIOMEM1: 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
1197INIT_VIDEO ENDP
1198
1199;
1200; Cleanup before returning to DOS
1201;
1202 ASSUME DS:NOTHING
1203CLEANUP 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
1216CLEANUP ENDP
1217
1218;
1219; Out of memory (real mode)
1220;
1221 ASSUME DS:SV_DATA
1222RM_OUT_OF_MEM: LEA DX, $RM_OUT_OF_MEM
1223 CALL RTEXT
1224 MOV AL, 0FFH
1225 JMP EXIT
1226
1227
1228INIT_CODE ENDS
1229
1230 END START
Note: See TracBrowser for help on using the repository browser.