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