source: vendor/emx/current/src/dos/syscall.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: 123.5 KB
Line 
1;
2; SYSCALL.ASM -- System calls (without BIOS and DOS calls)
3;
4; Copyright (c) 1991-1998 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; See emx.asm for a special exception.
24;
25
26 INCLUDE EMX.INC
27 INCLUDE SIGNAL.INC
28 INCLUDE PROCESS.INC
29 INCLUDE PAGING.INC
30 INCLUDE SEGMENTS.INC
31 INCLUDE LOADER.INC
32 INCLUDE FILEIO.INC
33 INCLUDE TABLES.INC
34 INCLUDE PMINT.INC
35 INCLUDE SWAPPER.INC
36 INCLUDE MEMORY.INC
37 INCLUDE VCPI.INC
38 INCLUDE MISC.INC
39 INCLUDE XMS.INC
40 INCLUDE CORE.INC
41 INCLUDE PROFIL.INC
42 INCLUDE VPRINT.INC
43 INCLUDE UTILS.INC
44 INCLUDE VERSION.INC
45 INCLUDE TERMIO.INC
46 INCLUDE STAT.INC
47 INCLUDE TIMEB.INC
48 INCLUDE ULIMIT.INC
49 INCLUDE ERRORS.INC
50
51 PUBLIC DO_SYSCALL
52
53FD_SETSIZE = 256
54
55MY_DATETIME STRUCT
56SECONDS DD ?
57MINUTES DD ?
58HOURS DD ?
59DAY DD ?
60MONTH DD ?
61YEAR DD ?
62MY_DATETIME ENDS
63
64SELECT_ARGS STRUCT
65SELA_NFDS DD ?
66SELA_READFDS DD ?
67SELA_WRITEFDS DD ?
68SELA_EXCEPTFDS DD ?
69SELA_TIMEOUT DD ?
70SELECT_ARGS ENDS
71
72TIMEVAL STRUCT
73TV_SEC DD ?
74TV_USEC DD ?
75TIMEVAL ENDS
76
77SV_DATA SEGMENT
78
79;
80; This structure is passed by spawnve() to NEW_PROCESS
81;
82 TALIGN 2
83NP2 NEW_PROC <>
84
85;
86; Variables for __select()
87;
88SEL_COUNT WORD ?
89SEL_RBITS BYTE FD_SETSIZE/8 DUP (?)
90
91;
92;
93;
94INO_NUMBER DWORD 100000H
95
96;
97; Number of days of a month
98;
99MONTH_LEN DB 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
100
101$FAT DB "FAT", 0
102$LAN DB "LAN", 0
103
104;
105; __open() maps "/dev/null" and "/dev/tty" to "nul" and "con",
106; respectively.
107;
108$DEVNULL BYTE "/dev/null", 0
109$DEVTTY BYTE "/dev/tty", 0
110$NUL BYTE "nul", 0
111$CON BYTE "con", 0
112
113;
114; Special program names
115;
116$COMMAND BYTE "COMMAND.COM", 0
117$4DOS BYTE "4DOS.COM", 0
118
119;
120; DOS_COMMAND sets this flag to non-FALSE if command.com or 4dos.com
121; is to be run.
122;
123IS_COMMAND BYTE FALSE
124
125;
126; Parameter block for DOS function 4BH
127;
128PAR_BLOCK LABEL BYTE
129PB_ENV DW 0
130 DD CMD_LINE ; Command line
131 DD FCB ; FCB1
132 DD FCB ; FCB2
133
134;
135; He who uses FCBs loses
136;
137FCB DB 0 ; Drive name
138 DB 11 DUP (" ") ; File name
139 DB 20 DUP (0) ; Fill to 32 bytes
140
141;
142; Program name and command line for DOS programs
143;
144PGM_NAME_SIZE = 65
145CMD_LINE_SIZE = 128
146
147PGM_NAME DB PGM_NAME_SIZE DUP (0)
148CMD_LINE DB CMD_LINE_SIZE DUP (0)
149
150FIND_BUF STRUC
151FIND_RESERVED DB 15H DUP (?)
152FIND_ATTR DB ?
153FIND_TIME DW ?
154FIND_DATE DW ?
155FIND_SIZE DD ?
156FIND_NAME DB 13 DUP (?)
157FIND_BUF ENDS
158
159STAT_CWD DB "x:\"
160 DB 65 DUP (?)
161
162;
163; Error message
164;
165$SYSCALL DB "Invalid syscall function code: 7f", 0
166
167SV_DATA ENDS
168
169SV_CODE SEGMENT
170
171 ASSUME CS:SV_CODE, DS:NOTHING
172
173TIME_2_UNIX PROTO PASCAL, MDT:PTR MY_DATETIME
174 EXTRN PTRACE:NEAR
175
176;
177; Jump table for syscall functions
178;
179 TALIGN 2
180SYSCALL_JMP DW SYS00 ; __sbrk
181 DW SYS01 ; __brk
182 DW SYS02 ; __ulimit
183 DW SYS03 ; __vmstat
184 DW SYS04 ; __umask1
185 DW SYS05 ; __getpid
186 DW SYS06 ; __spawnve
187 DW SYSCALL_ERROR ; (obsolete)
188 DW PTRACE ; __ptrace
189 DW SYS09 ; __wait
190 DW SYS0A ; __version
191 DW SYS0B ; __memavail
192 DW SYS0C ; __signal
193 DW SYS0D ; __kill
194 DW SYS0E ; __raise
195 DW SYS0F ; __uflags
196 DW SYS10 ; __unwind
197 DW SYS11 ; __core
198 DW SYS12 ; __portaccess
199 DW SYS13 ; __memaccess
200 DW SYS14 ; __ioctl2
201 DW SYS15 ; __alarm
202 DW SYS16 ; Poll the keyboard
203 DW SYS17 ; __sleep
204 DW SYS18 ; __chsize
205 DW SYS19 ; __fcntl
206 DW SYS1A ; __pipe
207 DW SYS1B ; __fsync
208 DW SYS1C ; __fork
209 DW SYS1D ; __scrsize
210 DW SYS1E ; __select
211 DW SYS1F ; __syserrno
212 DW SYS20 ; __stat
213 DW SYS21 ; __fstat
214 DW SYSCALL_ERROR ; No longer used
215 DW SYS23 ; __filesys
216 DW SYS24 ; __utimes
217 DW SYS25 ; __ftruncate
218 DW SYS26 ; __clock
219 DW SYS27 ; __ftime
220 DW SYS28 ; __umask
221 DW SYS29 ; __getppid
222 DW SYS2A ; __nls_memupr
223 DW SYS2B ; __open
224 DW SYS2C ; __newthread
225 DW SYS2D ; __endthread
226 DW SYS2E ; __waitpid
227 DW SYS2F ; __read_kbd
228 DW SYS30 ; __sleep2
229 DW SYS31 ; __unwind2
230 DW SYS32 ; __pause
231 DW SYS33 ; __execname
232 DW SYS34 ; __initthread
233 DW SYS35 ; __sigaction
234 DW SYS36 ; __sigpending
235 DW SYS37 ; __sigprocmask
236 DW SYS38 ; __sigsuspend
237 DW SYS39 ; __imphandle
238 DW SYS3A ; __fpuemu
239 DW SYSCALL_ERROR ; __getsockhandle
240 DW SYSCALL_ERROR ; __socket
241 DW SYSCALL_ERROR ; __bind
242 DW SYSCALL_ERROR ; __listen
243 DW SYSCALL_ERROR ; __recv
244 DW SYSCALL_ERROR ; __send
245 DW SYSCALL_ERROR ; __accept
246 DW SYSCALL_ERROR ; __connect
247 DW SYSCALL_ERROR ; __getsockopt
248 DW SYSCALL_ERROR ; __setsockopt
249 DW SYSCALL_ERROR ; __getsockname
250 DW SYSCALL_ERROR ; __getpeername
251 DW SYSCALL_ERROR ; __gethostbyname
252 DW SYSCALL_ERROR ; __gethostbyaddr
253 DW SYSCALL_ERROR ; __getservbyname
254 DW SYSCALL_ERROR ; __getservbyport
255 DW SYSCALL_ERROR ; __getprotobyname
256 DW SYSCALL_ERROR ; __getprotobynumber
257 DW SYSCALL_ERROR ; __getnetbyname
258 DW SYSCALL_ERROR ; __getnetbyaddr
259 DW SYSCALL_ERROR ; __gethostname
260 DW SYSCALL_ERROR ; __gethostid
261 DW SYSCALL_ERROR ; __shutdown
262 DW SYSCALL_ERROR ; __recvfrom
263 DW SYSCALL_ERROR ; __sendto
264 DW SYSCALL_ERROR ; __impsockhandle
265 DW SYSCALL_ERROR ; __recvmsg
266 DW SYSCALL_ERROR ; __sendmsg
267 DW SYSCALL_ERROR ; __ttyname
268 DW SYS58 ; __settime
269 DW SYS59 ; __profil
270 DW SYS5A ; __nls_ctype
271 DW SYSCALL_ENOSYS ; __setsyserrno
272SYSCALL_LAST = ($-SYSCALL_JMP)/2-1
273
274;
275; Syscall functions
276;
277; In: AH 7FH
278; AL Function code
279;
280 ASSUME DS:SV_DATA
281 ASSUME BP:PTR ISTACKFRAME
282 TALIGN 4
283DO_SYSCALL: CMP AL, SYSCALL_LAST ; Valid function code?
284 JA SHORT SYSCALL_ENOSYS ; Yes -> return ENOSYS
285 MOV DI, PROCESS_PTR ; Process table entry
286 MOVZX EAX, AL ; Keep only lower 8 bits
287 JMP SYSCALL_JMP[EAX*2] ; Jump!
288
289SYSCALL_ERROR: LEA EDX, $SYSCALL ; Display error message
290 MOV BL, AL ; (function code = AL)
291 JMP DOSF_ERROR ; and abort
292
293SYSCALL_ENOSYS: MOV I_EAX, -1
294 MOV I_ECX, ENOSYS
295 RET
296
297; ----------------------------------------------------------------------------
298; AX=7F00H: EAX:=sbrk(EDX)
299; AX=7F01H: EAX:=brk(EDX)
300;
301; Change data segment space allocation
302;
303; ----------------------------------------------------------------------------
304;
305; AX=7F00H: EAX:=sbrk(EDX)
306;
307; In: EDX Value to be added to current break value (address of
308; first byte beyond the end of the data segment). Positive
309; values grow the data segment, negative values shrink the
310; data segment.
311;
312; Out: EAX Previous break value or -1 if error.
313;
314; ----------------------------------------------------------------------------
315;
316; AX=7F01H: EAX:=brk(EDX)
317;
318; In: EDX New break value.
319;
320; Out: EAX 0 if successful or -1 if error.
321;
322; ----------------------------------------------------------------------------
323;
324; Bug: doesn't fail if there isn't enough swap space
325; Bug: Doesn't free pages with negative argument
326; Bug: Doesn't work with stack above data/bss!!!
327; Bug?: Doesn't zero-fill new memory
328;
329; ----------------------------------------------------------------------------
330 ASSUME DI:PTR PROCESS
331SYS00: MOV EAX, [DI].P_BRK ; Get current break value
332 PUSH EAX ; Save it
333 MOV EDX, I_EDX ; Get argument
334 CMP EDX, 0 ; No change?
335 JE SHORT SYS00_OK ; Yes -> done
336 JS SHORT SYS00_NEG
337 ADD EAX, EDX
338 JMP SHORT SYS00_1
339SYS00_NEG: NEG EDX
340 SUB EAX, EDX
341SYS00_1: JC SHORT SYS00_ERR
342 CALL BRK
343 JNC SHORT SYS00_OK
344SYS00_ERR: POP EAX ; Throw away saved value
345 MOV I_EAX, -1 ; Return -1
346 RET
347
348SYS00_OK: POP I_EAX ; Return previous break value
349 RET
350
351 ASSUME DI:NOTHING
352
353SYS01: MOV EAX, I_EDX ; Argument
354 CALL BRK
355 SBB EAX, EAX ; ok -> 0, error -> -1
356 MOV I_EAX, EAX
357 RET
358
359
360;
361; Common code for brk and sbrk
362;
363; In: DS:DI Pointer to process table entry
364; EAX New break value
365;
366; Out: CY Error
367;
368 ASSUME DI:PTR PROCESS
369BRK PROC NEAR
370 CMP EAX, [DI].P_INIT_BRK
371 JB BRK_ERR
372 MOV EBX, [DI].P_STACK_ADDR
373 CMP EBX, [DI].P_BRK ; Stack above data/bss ?
374 JB SHORT BRK_1 ; No -> don't check stack
375 SUB EBX, 4096 ; Leave at least one page
376 CMP EAX, EBX ; of stack space (note 1)
377 JA BRK_ERR ; Out of memory -> failure
378BRK_1: MOV ESI, EAX ; ESI := new break value
379 CMP EAX, [DI].P_BRK
380 JB SHORT BRK_SEG ; Set segment size
381 MOV ECX, EAX
382 DEC ECX ; New last byte
383 SHR ECX, 12 ; New last page number
384 MOV EAX, [DI].P_BRK
385 DEC EAX
386 JS SHORT BRK_2
387 SHR EAX, 12 ; Old last page number
388BRK_2: SUB ECX, EAX ; Number of new pages
389 JBE SHORT BRK_SEG
390 INC EAX ; First new page number
391 SHL EAX, 12 ; Byte address of new page
392 ADD EAX, [DI].P_LINEAR ; Linear address
393;
394; Note 1: We must not change the attributes of stack pages!
395; This is assured by leaving at least 4096 bytes between data
396; and stack.
397;
398 CALL INIT_PAGES
399 JC SHORT BRK_ERR ; Out of memory
400 MOV EBX, PAGE_WRITE OR PAGE_USER
401 MOV EDX, SRC_NONE
402 TEST [DI].P_FLAGS, PF_DONT_ZERO
403 JNZ SHORT BRK_3
404 MOV EDX, SRC_ZERO
405BRK_3: MOV DL, [DI].P_PIDX
406 CALL SET_COMMIT ; Set PAGE_ALLOC bit
407 CALL SET_PAGES
408 JC SHORT BRK_ERR ; Committing failed
409;
410; Adjust data segment size
411;
412BRK_SEG: MOV EBX, [DI].P_STACK_ADDR
413 CMP EBX, [DI].P_BRK ; Stack above data/bss ?
414 JA BRK_DONE ; Yes -> skip
415 MOV ECX, ESI
416 PUSH ESI
417 MOV SI, [DI].P_LDT_PTR
418 ADD SI, L_DATA_SEL AND NOT 07H
419 CALL SEG_SIZE
420 POP ESI
421BRK_DONE: MOV [DI].P_BRK, ESI
422 CLC
423 RET
424
425BRK_ERR: STC
426 RET
427
428 ASSUME DI:NOTHING
429BRK ENDP
430
431
432; ----------------------------------------------------------------------------
433; AX=7F02H: EAX:=ulimit
434;
435; Get greatest possible break value
436;
437; ----------------------------------------------------------------------------
438;
439; In: ECX Command code (must be UL_GMEMLIM or UL_OBJREST)
440; EDX New limit (currently ignored)
441;
442; Out: EAX Return value:
443; greatest possible break value for UL_GMEMLIM
444; remaining bytes in current heap object for UL_OBJREST
445; ECX errno, if non-zero
446;
447; ----------------------------------------------------------------------------
448
449 TALIGN 4
450 ASSUME DI:PTR PROCESS
451SYS02: CMP I_ECX, UL_GMEMLIM
452 JE ULIMIT_GMEMLIM
453 CMP I_ECX, UL_OBJREST
454 JE ULIMIT_OBJREST
455ULIMIT_ERR: MOV I_EAX, -1
456 MOV I_ECX, EINVAL
457 RET
458
459ULIMIT_OBJREST: CALL HEAP_LIMIT
460 SUB EAX, [DI].P_BRK
461 JMP SHORT ULIMIT_RET
462
463ULIMIT_GMEMLIM: CALL HEAP_LIMIT
464ULIMIT_RET: MOV I_EAX, EAX
465 MOV I_ECX, 0
466 RET
467
468HEAP_LIMIT PROC NEAR
469 MOV EAX, [DI].P_BRK ; Return this on error
470 MOV EDX, [DI].P_STACK_ADDR
471 CMP EDX, [DI].P_BRK
472 MOV EBX, 80000000H ; ...bad estimate
473 JB SHORT HEAP_LIMIT_1
474 MOV EBX, I_ESP
475 SUB EBX, 4096 ; Leave at least on page
476 JC SHORT HEAP_LIMIT_RET ; of stack space (note 1)
477HEAP_LIMIT_1: CMP EBX, [DI].P_BRK
478 JB SHORT HEAP_LIMIT_RET
479 MOV EAX, EBX
480HEAP_LIMIT_RET: RET
481HEAP_LIMIT ENDP
482
483 ASSUME DI:NOTHING
484
485; ----------------------------------------------------------------------------
486; AX=7F03H: [EBX]:=statistics
487;
488; Virtual memory statistics
489;
490; In: DS:EBX Buffer
491; ECX Size (in bytes) of buffer pointed to by DS:EBX
492;
493; Out: [EBX+0] Number of page faults caused by this process
494; [EBX+4] Total number of page faults
495;
496; ----------------------------------------------------------------------------
497 TALIGN 4
498 ASSUME DI:PTR PROCESS
499SYS03: MOV EBX, I_EBX
500 MOV ES, I_DS
501 MOV ECX, I_ECX
502 CMP ECX, 1*4
503 JB SHORT SYS03_RET
504 MOV EAX, [DI].P_PAGE_FAULTS
505 MOV ES:[EBX+0], EAX
506 CMP ECX, 2*4
507 JB SHORT SYS03_RET
508 MOV EAX, SWAP_FAULTS
509 MOV ES:[EBX+4], EAX
510SYS03_RET: RET
511
512 ASSUME DI:NOTHING
513
514; ----------------------------------------------------------------------------
515; AX=7F04H: EAX:=__umask1(EDX)
516;
517; Set file-permission mask
518;
519; ----------------------------------------------------------------------------
520 TALIGN 4
521 ASSUME DI:PTR PROCESS
522SYS04: MOVZX EAX, [DI].P_UMASK1
523 MOV I_EAX, EAX
524 MOV AX, WORD PTR I_EDX
525 NOT AX
526 AND [DI].P_UMASK1, AX
527 RET
528
529 ASSUME DI:NOTHING
530
531; ----------------------------------------------------------------------------
532; AX=7F05H: EAX:=getpid()
533;
534; Get process ID
535;
536; ----------------------------------------------------------------------------
537 TALIGN 4
538 ASSUME DI:PTR PROCESS
539SYS05: MOV EAX, [DI].P_PID
540 MOV I_EAX, EAX
541 RET
542
543 ASSUME DI:NOTHING
544
545; ----------------------------------------------------------------------------
546; AX=7F06H: spawnve()
547;
548; Spawn child process
549;
550; In: DS:EDX Pointer to parameter table (NEW_PROC, see PROCESS.INC)
551; NP_PARENT will be filled in by this function.
552;
553; Out: CY Error
554; NC Success
555; EAX Error code (CY)
556; EAX Process id (NC, asynchronous process)
557; EAX Return code (NC, synchronous process)
558;
559; Note: Not reentrant (uses global variable NP2!).
560;
561; ----------------------------------------------------------------------------
562 TALIGN 4
563 ASSUME DI:PTR PROCESS
564SYS06: MOV BX, DI
565 CALL SAVE_PROCESS ; Save registers
566 CALL MAKE_NP2 ; Copy param. table to NP2
567 CALL SPAWN_FNAME ; Create program file name
568 MOV NP2.NP_FNAME_SEL, DS
569 MOV NP2.NP_FNAME_OFF, OFFSET PGM_NAME
570 MOV DI, PROCESS_PTR ; Current process
571 CMP BYTE PTR NP2.NP_MODE1, NP_EXEC ; exec?
572 JNE SHORT SPAWN_2 ; No -> process is parent
573 MOV EAX, [DI].P_PPID ; PID of parent process
574 CALL FIND_PROCESS ; Find parent process
575 CMP BX, NO_PROCESS ; Success?
576 JNE SHORT SPAWN_2 ; Yes -> has real parent
577 LEA BX, PROC0 ; No -> use dummy parent
578SPAWN_2: MOV NP2.NP_PARENT, BX ; Set NP_PARENT field
579 MOV NP2.NP_FPROC, DI ; Set source of file handles
580 LEA SI, NP2 ; Parameter table
581 CALL NEW_PROCESS ; Create new process
582 OR AX, AX ; Failure?
583 JNZ SHORT SPAWN_FAIL ; Yes -> try DOS pgm or return
584 MOV BX, PROCESS_PTR ; Outgoing process
585 ASSUME BX:PTR PROCESS
586 CMP BYTE PTR NP2.NP_MODE1, NP_DEBUG ; Debugging?
587 JE SHORT SPAWN_ASYNC ; Yes -> return to parent
588 CMP BYTE PTR NP2.NP_MODE1, NP_SPAWN_ASYNC ; Asynchronous?
589 JNE SHORT SPAWN_3 ; No -> continue
590 MOV EAX, [DI].P_PID ; Process ID of child
591 MOV [BX].P_SPAWN_RC, EAX ; will be returned by spawn()
592 OR [BX].P_FLAGS, PF_PSEUDO_ASYNC
593SPAWN_3: MOV [BX].P_STATUS, PS_WAIT_SPAWN
594;
595; Now run the new process synchronously
596;
597 MOV PROCESS_PTR, DI ; Switch to incoming process
598 MOV PROCESS_SIG, DI
599 CMP BYTE PTR NP2.NP_MODE1, NP_EXEC
600 JNE SHORT SPAWN_4
601 CALL REMOVE_PROCESS ; TODO: FPUEMU_ENDPROC
602SPAWN_4: MOV BX, DI
603 CALL REST_PROCESS ; Start incoming process
604 CALL BREAK_AFTER_IRET
605 MOV EAX, [BX].P_NUMBER
606 CALL FPUEMU_NEWPROC ; Notify FPU emulator
607SPAWN_RET: RET
608
609;
610; Return to the parent process after starting an asynchronous process.
611; This is currently used for NP_DEBUG only.
612;
613SPAWN_ASYNC: MOV EAX, [DI].P_PID ; Process ID of child
614 MOV I_EAX, EAX ; Return process ID
615 MOV EAX, [DI].P_NUMBER
616 CALL FPUEMU_NEWPROC ; Notify FPU emulator
617 JMP SHORT SPAWN_RET
618
619SPAWN_FAIL: CMP AX, ENOEXEC ; Not an emx program?
620 JE SHORT SPAWN_DOS ; Yes -> try to run a DOS pgm
621SPAWN_ERROR: MOVZX EAX, AX
622 MOV I_EAX, EAX ; Failure
623 OR BYTE PTR I_EFLAGS, FLAG_C
624 RET
625
626 ASSUME BX:NOTHING
627 ASSUME DI:NOTHING
628;
629; Try to run the program as ordinary DOS program
630;
631SPAWN_DOS: CMP BYTE PTR NP2.NP_MODE1, NP_SPAWN_SYNC ; Synchronous?
632 JE SHORT SPAWN_DOS_1 ; Yes -> continue
633 CMP BYTE PTR NP2.NP_MODE1, NP_SPAWN_ASYNC ; Asynchronous?
634 JNE SHORT SPAWN_ERROR ; No -> error
635SPAWN_DOS_1: CMP DISABLE_LOW_MEM, FALSE ; Low memory in use?
636 JNE SHORT DOS_10 ; No -> ok
637 MOV AX, ENOMEM ; Not enough memory
638 JMP SHORT SPAWN_ERROR
639;
640; Build command line
641;
642DOS_10: CALL DOS_COMMAND ; Look for COMMAND.COM
643 CALL DOS_ARGS ; Build command line
644 JC SHORT DOS_TOO_BIG
645 CALL DOS_ENV ; Build environment
646 OR AX, AX
647 JNZ SHORT SPAWN_ERROR ; Error -> return errno
648 CALL MAP_ALL_HANDLES ; Remap file handles
649 JC SHORT SPAWN_ERROR ; Error -> return errno
650;
651; Try to run the program
652;
653 LEA DX, PGM_NAME
654 LEA BX, PAR_BLOCK
655 MOV AX, 4B00H ; Load and execute program
656 INT 21H
657 MOV I_EAX, EAX
658 JNC SHORT DOS_OK
659 OR BYTE PTR I_EFLAGS, FLAG_C
660 JMP SPAWN_RET
661
662DOS_OK: MOV AH, 4DH ; Get ret code of child process
663 INT 21H
664 MOVZX EAX, AX ; Put it in EAX
665 MOV BX, PROCESS_PTR ; Parent process
666 ASSUME BX:PTR PROCESS
667 CMP BYTE PTR NP2.NP_MODE1, NP_SPAWN_ASYNC ; Pseudo async?
668 JNE SHORT DOS_SPAWN_RC ; No -> return return code
669 MOV [BX].P_RC, AL ; Save the return code
670 CALL CREATE_PID ; Return a process ID
671 OR [BX].P_FLAGS, PF_PSEUDO_ASYNC
672 CMP [BX].P_SIG_HANDLERS[4*SIGCLD], SIG_IGN
673 JE SHORT DOS_SPAWN_RC
674 CMP [BX].P_SIG_HANDLERS[4*SIGCLD], SIG_DFL
675 JE SHORT DOS_SPAWN_RC
676 BTS [BX].P_SIG_PENDING, SIGCLD ; Generate SIGCLD
677DOS_SPAWN_RC: MOV [BX].P_SPAWN_RC, EAX
678 MOV I_EAX, EAX
679 JMP SPAWN_RET
680 ASSUME BX:NOTHING
681
682;
683; Arguments or environment too big
684;
685DOS_TOO_BIG: MOV AX, E2BIG
686 JMP SPAWN_ERROR
687
688;
689;
690;
691 TALIGN 4
692SPAWN_FNAME PROC NEAR
693 PUSH ESI
694 PUSH EDI
695 PUSH DS
696 LEA DI, PGM_NAME
697 MOV_ES_DS
698 MOV ESI, NP2.NP_FNAME_OFF
699 MOV DS, NP2.NP_FNAME_SEL
700 ASSUME DS:NOTHING
701 MOV CX, PGM_NAME_SIZE - 1
702SPAWN_FNAME_1: LODS BYTE PTR DS:[ESI]
703 OR AL, AL
704 JZ SHORT SPAWN_FNAME_2
705 STOS BYTE PTR ES:[DI]
706 LOOP SPAWN_FNAME_1
707SPAWN_FNAME_2: XOR AL, AL
708 STOS BYTE PTR ES:[DI]
709 POP DS
710 ASSUME DS:SV_DATA
711 LEA EDI, PGM_NAME
712 CALL TRUNCATE
713 POP EDI
714 POP ESI
715 RET
716SPAWN_FNAME ENDP
717
718;
719; Check for COMMAND.COM and 4DOS.COM
720;
721
722DOS_COMMAND PROC NEAR
723 MOV IS_COMMAND, FALSE ; Standard quoting by default
724 LEA SI, PGM_NAME ; Find base name
725 MOV DI, SI
726DC_1: LODSB
727 OR AL, AL
728 JZ SHORT DC_3
729 CMP AL, "/"
730 JE SHORT DC_2
731 CMP AL, "\"
732 JE SHORT DC_2
733 CMP AL, ":"
734 JNE SHORT DC_1
735DC_2: MOV DI, SI
736 JMP SHORT DC_1
737
738DC_3: MOV_ES_DS
739 LEA SI, $COMMAND ; command.com?
740 CALL STRICMP
741 JE SHORT DC_4 ; Yes ->
742 LEA SI, $4DOS ; 4dos.com?
743 CALL STRICMP
744 JNE SHORT DC_RET ; No -> skip
745DC_4: MOV IS_COMMAND, NOT FALSE ; Don't quote arguments
746DC_RET: RET
747DOS_COMMAND ENDP
748
749;
750; Build command line for DOS programs
751;
752; In: NP2 Parameter block
753;
754; Out: CY Command line too big
755;
756DOS_ARGS PROC NEAR PASCAL
757 LOCAL ARG_COUNTER:WORD
758 LOCAL NO_QUOTE:BYTE
759 LOCAL FORCE_QUOTE:BYTE
760
761 PUSH DS ; Save DS
762 MOV AL, IS_COMMAND ; No quoting if command.com
763 MOV NO_QUOTE, AL ; Copy to stack segment
764 MOV FORCE_QUOTE, FALSE
765 TEST NP2.NP_MODE2, NP2_QUOTE
766 JNZ SHORT DA_1
767 MOV BX, PROCESS_PTR
768 CMP BX, NO_PROCESS
769 JE SHORT DA_2
770 TEST (PROCESS PTR [BX]).P_FLAGS, PF_QUOTE
771 JZ SHORT DA_2
772DA_1: NOT FORCE_QUOTE
773DA_2: MOV DX, 0 ; Size of command line
774 MOV AX, NP2.NP_ARG_COUNT ; Number of arguments
775 MOV_ES_DS
776 LEA DI, CMD_LINE + 1
777 MOV ESI, NP2.NP_ARG_OFF
778 MOV DS, NP2.NP_ARG_SEL
779 ASSUME DS:NOTHING
780 CLD
781;
782; Skip argv[0]
783;
784 CMP AX, 2
785 JB DONE ; No arguments -> done
786 DEC AX ; argv[0] skipped
787 MOV ARG_COUNTER, AX
788 LODS BYTE PTR DS:[ESI] ; Get flags byte
789 OR AL, AL ; End of arguments?
790 JZ DONE ; Yes -> done
791SKIP_ARGV0: LODS BYTE PTR DS:[ESI] ; Fetch character
792 OR AL, AL ; End of argument?
793 JNZ SKIP_ARGV0 ; No -> repeat
794;
795; Next argument
796;
797NEXT: LODS BYTE PTR DS:[ESI] ; Get flags byte
798 OR DX, DX
799 JZ SHORT ARG_SKIP_FLAG ; First argument -> skip
800 INC DX
801 CMP DX, CMD_LINE_SIZE - 2 ; Too long?
802 JA DONE ; Yes -> end
803 MOV AL, " " ; Delimit arguments
804 STOS BYTE PTR ES:[DI]
805;
806; Look for blanks and tabs. Quote the entire argument if there is
807; a blank or a tab.
808;
809ARG_SKIP_FLAG: CMP NO_QUOTE, FALSE ; Quote?
810 JNE SHORT ARG_CHECK_NO ; No -> skip
811 CMP BYTE PTR DS:[ESI], 0 ; Empty argument?
812 JE SHORT ARG_CHECK_YES ; Yes -> needs quoting
813 PUSH ESI
814 XOR AH, AH ; No quoting required
815ARG_CHECK: LODS BYTE PTR DS:[ESI] ; Fetch character
816 TEST AL, AL ; End of argument?
817 JZ SHORT ARG_CHECK_END ; Yes -> no quoting required
818 CMP AL, " " ; Blank?
819 JE SHORT ARG_CHECK_END ; Yes -> quote the argument
820 CMP AL, TAB ; Tab?
821 JNE SHORT ARG_CHECK ; No -> check next character
822ARG_CHECK_END: POP ESI
823 TEST AL, AL
824 JNZ SHORT ARG_CHECK_YES
825 CMP FORCE_QUOTE, FALSE ; P_QUOTE or -q?
826 JE SHORT ARG_CHECK_NO ; No -> don't quote
827;
828; Check for @, ? or *
829;
830 PUSH ESI
831 MOV AL, 1
832 CMP BYTE PTR DS:[ESI], "@" ; Argument starting with "@"?
833 JNE SHORT AC_200
834 CMP BYTE PTR DS:[ESI+1], 0
835 JNE SHORT AC_299 ; Yes -> quote (AL non-zero)
836AC_200: LODS BYTE PTR DS:[ESI] ; Fetch character
837 TEST AL, AL ; End of argument?
838 JZ SHORT AC_299 ; Yes -> don't quote (AL=0)
839 CMP AL, "?" ; Wildcard character?
840 JE SHORT AC_299 ; Yes -> quote (AL non-zero)
841 CMP AL, "*" ; Wildcard character?
842 JNE SHORT AC_200 ; No -> check next character
843AC_299: POP ESI
844 TEST AL, AL
845 JZ SHORT ARG_CHECK_NO
846ARG_CHECK_YES: MOV AH, 1 ; Flag for closing quote
847 INC DX
848 CMP DX, CMD_LINE_SIZE - 2 ; Too long?
849 JA SHORT DONE ; Yes -> end
850 MOV AL, '"' ; Store opening quote
851 STOS BYTE PTR ES:[DI]
852ARG_CHECK_NO: XOR CX, CX ; Clear backslash counter
853;
854; Copy argument
855;
856ARG_COPY: LODS BYTE PTR DS:[ESI] ; Fetch character
857 OR AL, AL ; End of argument?
858 JZ SHORT ARG_END ; Yes -> next argument
859 CMP NO_QUOTE, FALSE ; Quoting disabled?
860 JNE SHORT ARG_STORE ; Yes -> simply store the char
861 CMP AL, "\" ; Backslash?
862 JE SHORT ARG_BACKSLASH ; Yes -> count
863 CMP AL, '"' ; Quote?
864 JE SHORT ARG_QUOTE ; Yes -> handle backslashes
865 XOR CX, CX ; Clear backslash counter
866ARG_STORE: INC DX
867 CMP DX, CMD_LINE_SIZE - 2 ; Too long?
868 JA SHORT DONE ; Yes -> end
869 STOS BYTE PTR ES:[DI]
870 JMP SHORT ARG_COPY
871
872 TALIGN 4
873ARG_BACKSLASH: INC CX ; Increment backslash counter
874 JMP SHORT ARG_STORE ; Store character
875
876 TALIGN 4
877ARG_QUOTE: INC CX ; 2n+1 backslashes
878 ADD DX, CX
879 CMP DX, CMD_LINE_SIZE - 2 ; Too long?
880 JA SHORT DONE ; Yes -> end
881 MOV AL, "\" ; Store backslashes
882ARG_QUOTE_1: STOSB
883 LOOP ARG_QUOTE_1
884 MOV AL, '"'
885 JMP SHORT ARG_STORE
886
887ARG_END: OR AH, AH ; Closing quote required?
888 JZ SHORT MORE ; No -> skip
889 JCXZ ARG_END_2
890 ADD DX, CX
891 CMP DX, CMD_LINE_SIZE - 2 ; Too long?
892 JA SHORT DONE ; Yes -> end
893 MOV AL, "\"
894ARG_END_1: STOSB
895 LOOP ARG_END_1
896ARG_END_2: MOV AL, '"'
897 INC DX
898 CMP DX, CMD_LINE_SIZE - 2 ; Too long?
899 JA SHORT DONE ; Yes -> end
900 STOSB
901MORE: DEC ARG_COUNTER
902 JNZ NEXT
903DONE: POP DS ; Restore DS
904 ASSUME DS:SV_DATA
905 CMP DX, CMD_LINE_SIZE - 2
906 JA SHORT TOO_BIG
907 MOV CMD_LINE[0], DL ; Length = 0
908 MOV AL, CR
909 STOS BYTE PTR ES:[DI] ; End of command line
910 CLC
911FIN: RET
912
913TOO_BIG: STC
914 JMP SHORT FIN
915DOS_ARGS ENDP
916
917
918; ----------------------------------------------------------------------------
919;
920; Build environment for DOS program
921;
922; Out: AX errno (0 if no error)
923; PB_ENV Segment of environment
924;
925; ----------------------------------------------------------------------------
926DOS_ENV PROC NEAR
927 CMP NP2.NP_ENV_SIZE, 8000H ; Fail with E2BIG if the
928 MOV AX, E2BIG ; environment is too big
929 JAE SHORT ERR
930;
931; Copy the environment to the real-mode buffer (that buffer is not used
932; for INT 21H, AH=4BH).
933;
934 MOV AX, NP2.NP_ENV_SEL
935 MOV ESI, NP2.NP_ENV_OFF
936 MOV EDI, 0 ; OFFSET_1 is not zero!
937 MOVZX ECX, NP2.NP_ENV_SIZE
938 CALL MOVE_TO_RM
939 MOV AX, BUF_SEG ; Set the environment pointer
940 MOV PB_ENV, AX ; in the parameter block
941OK: XOR AX, AX ; No error
942ERR: RET
943DOS_ENV ENDP
944
945
946; ----------------------------------------------------------------------------
947; Copy NEW_PROC (_new_proc) structure from user process' data segment to
948; supervisor data segment
949;
950; In: I_EDX Pointer to structure in user process' data segment
951;
952; ----------------------------------------------------------------------------
953 TALIGN 4
954MAKE_NP2 PROC NEAR
955 PUSH DS
956 XOR EDI, EDI
957 LEA DI, NP2
958 MOV_ES_DS
959 MOV ESI, I_EDX
960 MOV DS, I_DS
961 ASSUME DS:NOTHING
962 MOV ECX, NP_USER_SIZE
963 REP MOVS BYTE PTR ES:[EDI], BYTE PTR DS:[ESI]
964 POP DS
965 ASSUME DS:SV_DATA
966 MOV NP2.NP_MODE2, 0
967 TEST NP2.NP_MODE1, 8000H
968 JZ SHORT MNP2_1
969 MOV ES, I_DS
970 MOV ESI, I_EDX
971 ASSUME ESI:NEAR32 PTR NEW_PROC
972 MOV AX, ES:[ESI].NP_MODE2
973 MOV NP2.NP_MODE2, AX
974 ASSUME ESI:NOTHING
975MNP2_1: RET
976MAKE_NP2 ENDP
977
978
979; ----------------------------------------------------------------------------
980; AX=7F09H: __wait()
981;
982; Wait for child process
983;
984; In: --
985;
986; Out: EAX Process ID of child process (-1 if no children)
987; ECX errno
988; EDX Termination status
989;
990; ----------------------------------------------------------------------------
991 TALIGN 4
992 ASSUME DI:PTR PROCESS
993SYS09: TEST [DI].P_FLAGS, PF_PSEUDO_ASYNC ; Pseudo async child?
994 JNZ SHORT WAIT_PSEUDO ; Yes -> return its status
995 MOV EAX, [DI].P_PID ; Get process ID
996 CALL WAIT_PROCESS ; Look for children
997 CMP BX, NO_PROCESS ; Children?
998 JE SHORT SYS09_ERROR ; No -> error
999 CMP BX, NO_WPROCESS ; Stopped/terminated children?
1000 JE SHORT SYS09_WAIT ; No -> wait
1001 ASSUME BX:PTR PROCESS
1002 AND [BX].P_FLAGS, NOT PF_WAIT_WAIT ; wait done
1003 MOV EAX, [BX].P_PID ; Return process ID
1004 MOV I_EAX, EAX
1005 XOR EAX, EAX ; Termination status := 0
1006 CMP [BX].P_STATUS, PS_STOP ; Stopped process?
1007 JE SHORT SYS09_STOP ; Yes ->
1008 MOV AH, [BX].P_RC ; Return code -> bits 8..15
1009 JMP SHORT SYS09_OK
1010SYS09_STOP: MOV AL, 177Q
1011 MOV AH, [BX].P_SIG_NO ; Signal number
1012SYS09_OK: MOV I_EDX, EAX ; Return status in EDX
1013 MOV I_ECX, 0 ; No error
1014 CMP [BX].P_STATUS, PS_DEFUNCT ; Zombie process?
1015 JNE SHORT SYS09_RET ; No -> skip
1016 CALL KILL_PROCESS ; Remove last vestiges
1017 ASSUME BX:NOTHING
1018SYS09_RET: RET
1019
1020
1021;
1022; There are children, but no one stopped/terminated. Wait.
1023; Not implemented, return error.
1024;
1025SYS09_WAIT:
1026SYS09_ERROR: MOV I_ECX, ECHILD
1027 MOV I_EAX, -1
1028 RET
1029
1030;
1031; We had a pseudo asynchronous child process. Return its termination
1032; status.
1033;
1034WAIT_PSEUDO: AND [DI].P_FLAGS, NOT PF_PSEUDO_ASYNC ; Child is dead
1035 XOR EAX, EAX
1036 MOV AH, [DI].P_RC ; Get the return code
1037 MOV I_EDX, EAX ; Set termination status
1038 MOV EAX, [DI].P_SPAWN_RC ; Process ID
1039 MOV I_EAX, EAX
1040 MOV I_ECX, 0 ; No error
1041 RET
1042
1043 ASSUME DI:NOTHING
1044
1045
1046; ----------------------------------------------------------------------------
1047; AX=7F0AH: version
1048;
1049; Return emx version
1050;
1051; In: --
1052;
1053; Out: EAX Version number
1054; Bits 0..7: version letter ("a".."z")
1055; Bits 8..15: minor version number ("0".."9")
1056; Bits 16..23: 2EH (".")
1057; Bits 24..31: major version number ("0".."9")
1058; EBX Environment:
1059; Bit 0: VCPI
1060; Bit 1: XMS
1061; Bit 2: VDISK.SYS 3.3
1062; Bit 3: DESQview
1063; Bit 4: 287
1064; Bit 5: 387
1065; Bit 6: 486 (not implemented)
1066; Bit 7: DPMI 0.9 (not implemented)
1067; Bit 8: DPMI 1.0 (not implemented)
1068; Bit 9: OS/2 2.0
1069; Bit 10: -t option given
1070; Bits 6..31: 0 (reserved for future expansion)
1071; ECX Revision index
1072; EDX 0 (reserved for future expansion)
1073;
1074; ----------------------------------------------------------------------------
1075 TALIGN 4
1076 ASSUME DI:PTR PROCESS
1077SYS0A: MOV I_EAX, VERSION ; Return version number in EAX
1078 XOR EAX, EAX ; Clear all environment bits
1079 CMP VCPI_FLAG, FALSE
1080 JE SHORT SYS0A_1
1081 OR AL, 01H ; Set VCPI bit
1082SYS0A_1: CMP XMS_FLAG, FALSE
1083 JE SHORT SYS0A_2
1084 OR AL, 02H ; Set XMS bit
1085SYS0A_2: CMP VDISK_FLAG, FALSE
1086 JE SHORT SYS0A_3
1087 OR AL, 04H ; Set VDISK bit
1088SYS0A_3: CMP DV_FLAG, FALSE
1089 JE SHORT SYS0A_4
1090 OR AL, 08H ; Set DESQview bit
1091SYS0A_4: CMP FP_FLAG, FP_287
1092 JNE SHORT SYS0A_5
1093 OR AL, 10H ; Set 287 bit
1094SYS0A_5: CMP FP_FLAG, FP_387
1095 JNE SHORT SYS0A_6
1096 OR AL, 20H ; Set 387 bit
1097SYS0A_6: CMP [DI].P_TRUNC, 0
1098 JE SHORT SYS0A_7
1099 OR AX, 400H ; Set -t bit
1100SYS0A_7: TEST [DI].P_HW_ACCESS, HW_ACCESS_CODE
1101 JZ SHORT SYS0A_8
1102 OR AX, 800H ; Set -ac bit
1103SYS0A_8: MOV I_EBX, EAX
1104 MOV I_ECX, REV_INDEX_BIN ; Revision index
1105 MOV I_EDX, 0 ; Reserved
1106 RET
1107
1108 ASSUME DI:NOTHING
1109
1110; ----------------------------------------------------------------------------
1111; AX=7F0BH: memavail
1112;
1113; Return number of available pages of memory (w/o swapping)
1114;
1115; In: --
1116;
1117; Out: EAX Number of available pages
1118;
1119; ----------------------------------------------------------------------------
1120 TALIGN 4
1121SYS0B: CALL PM_AVAIL ; This call does all the work
1122 MOV I_EAX, EAX ; Return the result in EAX
1123 RET
1124
1125; ----------------------------------------------------------------------------
1126; AX=7F0CH: __signal()
1127;
1128; Set signal handler
1129;
1130; In: ECX Signal number
1131; EDX Address of signal handler or SIG_ACK, SIG_DFL, SIG_IGN
1132;
1133; Out: EAX Previous value (success) or SIG_ERR (error)
1134;
1135; ----------------------------------------------------------------------------
1136 TALIGN 4
1137 ASSUME DI:PTR PROCESS
1138SYS0C: MOV EAX, I_ECX ; Signal number
1139 MOV EDX, I_EDX ; Signal handler
1140 CMP EDX, SIG_ACK ; Acknowledge?
1141 JE SHORT SIGNAL_ACK ; Yes ->
1142 CALL DO_SIGNAL
1143 MOV I_EAX, EAX
1144 RET
1145
1146;
1147; Unblock the signal EAX. If there is a pending signal, it will be
1148; raised on return to the current process.
1149;
1150SIGNAL_ACK: CMP EAX, SIGNALS ; Valid signal number?
1151 JAE SHORT SIGNAL_ERROR ; No -> failure
1152 CMP SIG_VALID[EAX], FALSE
1153 JE SHORT SIGNAL_ERROR ; No -> failure
1154 MOV BX, AX
1155 SHL BX, 2
1156 TEST [DI].P_SA_FLAGS[BX], SA_ACK ; SA_ACK set?
1157 JZ SHORT SIGNAL_ERROR ; No -> failure
1158 BTR [DI].P_SIG_BLOCKED, EAX ; Unblock the signal
1159 MOV EAX, [DI].P_SIG_HANDLERS[BX] ; Get previous value
1160 MOV I_EAX, EAX ; Return previous value
1161 RET
1162
1163SIGNAL_ERROR: MOV I_EAX, SIG_ERR ; Return SIG_ERR
1164 RET
1165
1166 ASSUME DI:NOTHING
1167
1168; ----------------------------------------------------------------------------
1169; AX=7F0DH: __kill()
1170;
1171; Send a signal to a process
1172;
1173; In: ECX Signal number
1174; EDX Process ID
1175;
1176; Out: EAX 0 if successful, -1 otherwise
1177; ECX errno
1178;
1179; (As we don't have real multitasking, we should switch to the other
1180; process.)
1181;
1182; ----------------------------------------------------------------------------
1183 TALIGN 4
1184SYS0D: MOV EAX, I_EDX ; Get process ID
1185 CALL FIND_PROCESS ; Find process for given ID
1186 CMP BX, NO_PROCESS ; Found?
1187 JE SHORT KILL_BAD_PID ; No -> error
1188 CMP I_ECX, 0 ; Signal 0 (check PID)?
1189 JE SHORT RAISE_OK ; Yes -> ok
1190 MOV DI, BX ; Copy process pointer to DI
1191;
1192; Fall through to __raise() code
1193;
1194; ----------------------------------------------------------------------------
1195; AX=7F0EH: __raise()
1196;
1197; Raise a signal (in current process)
1198;
1199; In: ECX Signal number
1200;
1201; Out: EAX 0 if successful, a non-zero value otherwise
1202; ECX errno
1203;
1204; ----------------------------------------------------------------------------
1205 TALIGN 4
1206 ASSUME DI:PTR PROCESS
1207SYS0E: MOV EAX, I_ECX ; Get signal number
1208 CMP EAX, SIGNALS ; Valid signal number?
1209 JAE SHORT RAISE_ERROR ; No -> failure
1210 CMP SIG_VALID[EAX], FALSE
1211 JE SHORT RAISE_ERROR ; No -> failure
1212 BTS [DI].P_SIG_PENDING, EAX ; Generate signal
1213RAISE_OK: MOV I_ECX, 0 ; No error
1214 MOV I_EAX, 0 ; Success
1215 RET
1216
1217RAISE_ERROR: MOV I_ECX, EINVAL
1218 MOV I_EAX, -1 ; Error
1219 RET
1220
1221KILL_BAD_PID: MOV I_ECX, ESRCH
1222 MOV I_EAX, -1
1223 RET
1224
1225 ASSUME DI:NOTHING
1226
1227; ----------------------------------------------------------------------------
1228; AX=7F0FH: EAX:=uflags(ECX,EDX)
1229;
1230; Set user flags
1231;
1232; ----------------------------------------------------------------------------
1233 TALIGN 4
1234 ASSUME DI:PTR PROCESS
1235SYS0F: MOV EAX, [DI].P_UFLAGS
1236 MOV I_EAX, EAX ; Return previous value
1237 MOV ECX, I_ECX ; Get mask
1238 MOV EDX, I_EDX ; Get new bits
1239 AND EDX, ECX ; Clear unwanted bits
1240 NOT ECX
1241 AND EAX, ECX ; Clear bits to be changed
1242 OR EAX, EDX ; Insert new bits
1243 MOV [DI].P_UFLAGS, EAX ; Store new value
1244 RET
1245
1246 ASSUME DI:NOTHING
1247
1248; ----------------------------------------------------------------------------
1249; AX=7F10H: __unwind()
1250;
1251; Unwind signal handlers for longjmp()
1252;
1253; Currently not used by the DOS version of emx.
1254;
1255; ----------------------------------------------------------------------------
1256
1257 TALIGN 4
1258SYS10: RET
1259
1260; ----------------------------------------------------------------------------
1261; AX=7F11H: __core()
1262;
1263; Write core image file
1264;
1265; In: EBX File handle
1266;
1267; Out: CY Error
1268; EAX errno (CY)
1269;
1270; ----------------------------------------------------------------------------
1271
1272 TALIGN 4
1273SYS11: MOV BX, DI ; Process table entry
1274 CALL CORE_REGS_I
1275 MOV EAX, I_EBX ; Get file handle
1276 CALL CORE_MAIN ; Write core image file
1277 JNC SHORT SYS11_RET
1278 OR I_EFLAGS, FLAG_C
1279 CALL DOS_ERROR_TO_ERRNO
1280 MOV I_EAX, EAX
1281SYS11_RET: RET
1282
1283; ----------------------------------------------------------------------------
1284; AX=7F12H: _portaccess()
1285;
1286; Enable access to I/O ports
1287;
1288; In: ECX First port number
1289; EDX Last port number
1290;
1291; Out: CY Failed
1292; EAX errno (0 if successful)
1293;
1294; ----------------------------------------------------------------------------
1295
1296 TALIGN 4
1297 ASSUME DI:PTR PROCESS
1298SYS12: MOV EAX, I_ECX
1299 CMP EAX, 10000H
1300 JAE SHORT PORTACCESS_ERR
1301 MOV ECX, I_EDX
1302 CMP ECX, 10000H
1303 JAE SHORT PORTACCESS_ERR
1304 SUB ECX, EAX
1305 JB SHORT PORTACCESS_ERR
1306 INC ECX
1307 TEST [DI].P_HW_ACCESS, HW_ACCESS_IO
1308 JZ SHORT PORTACCESS_ERR
1309 CMP NEW_TSS, FALSE
1310 JE SHORT PORTACCESS_ERR
1311 MOV DX, G_TSS_MEM_SEL
1312 MOV FS, DX
1313 MOVZX EBX, (TSS_STRUC PTR FS:[0]).TSS_BIT_MAP_OFF
1314PORTACCESS_1: BTR DWORD PTR FS:[EBX], EAX
1315 INC EAX
1316 LOOPD PORTACCESS_1
1317 MOV I_EAX, 0
1318 RET
1319
1320PORTACCESS_ERR: MOV I_EAX, EACCES
1321 OR I_EFLAGS, FLAG_C
1322 RET
1323
1324 ASSUME DI:NOTHING
1325
1326; ----------------------------------------------------------------------------
1327; AX=7F13H: _memaccess()
1328;
1329; Enable access to memory
1330;
1331; In: EBX First address
1332; ECX Last address
1333; EDX 0: read access, 1:write access
1334;
1335; Out: CY Failed
1336; EAX errno if failed (CY)
1337; EAX Pointer to start of mapped memory area (NC)
1338;
1339; ----------------------------------------------------------------------------
1340
1341 TALIGN 4
1342 ASSUME DI:PTR PROCESS
1343SYS13: CMP I_EDX, 1
1344 JA MEMACCESS_INV
1345 MOV EAX, I_EBX
1346 TEST EAX, 0FFFH
1347 JNZ MEMACCESS_ACC
1348 MOV ECX, I_ECX
1349 INC ECX
1350 JNZ SHORT MEMACCESS_01
1351 OR EAX, EAX
1352 JZ MEMACCESS_MEM
1353 SUB ECX, EAX
1354 JMP SHORT MEMACCESS_02
1355MEMACCESS_01: TEST ECX, 0FFFH
1356 JNZ MEMACCESS_ACC
1357 SUB ECX, EAX
1358 JBE MEMACCESS_ACC
1359MEMACCESS_02: TEST [DI].P_HW_ACCESS, HW_ACCESS_MEM
1360 JZ MEMACCESS_ACC
1361 MOV EBX, I_EBX
1362 OR EBX, PAGE_PRESENT OR PAGE_USER OR PAGE_LOCKED
1363 CMP I_EDX, 0
1364 JE SHORT MEMACCESS_RD
1365 CMP I_EBX, 0A0000H
1366 JB SHORT MEMACCESS_DNG ; Danger!
1367 CMP I_ECX, 0BFFFFH
1368 JBE SHORT MEMACCESS_WR
1369MEMACCESS_DNG: TEST [DI].P_HW_ACCESS, HW_ACCESS_WRITE
1370 JZ SHORT MEMACCESS_ACC
1371MEMACCESS_WR: OR EBX, PAGE_WRITE
1372MEMACCESS_RD: MOV EDX, SRC_NONE
1373 SHR ECX, 12
1374 CALL MAP_PHYS
1375 TEST EAX, EAX
1376 JZ SHORT MEMACCESS_MEM
1377 MOV I_EAX, EAX
1378 RET
1379
1380MEMACCESS_INV: MOV I_EAX, EINVAL
1381 OR I_EFLAGS, FLAG_C
1382 RET
1383
1384MEMACCESS_ACC: MOV I_EAX, EACCES
1385 OR I_EFLAGS, FLAG_C
1386 RET
1387
1388MEMACCESS_MEM: MOV I_EAX, ENOMEM
1389 OR I_EFLAGS, FLAG_C
1390 RET
1391
1392 ASSUME DI:NOTHING
1393
1394; ----------------------------------------------------------------------------
1395; AX=7F14H: __ioctl2()
1396;
1397; UNIX-like termio ioctl()
1398;
1399; In: EBX Handle
1400; ECX Request code
1401; EDX Argument
1402;
1403; Out: EAX Return value
1404; ECX errno
1405;
1406; ----------------------------------------------------------------------------
1407
1408 TALIGN 4
1409SYS14: CMP I_ECX, TCGETA
1410 JE SHORT TC_GETA
1411 CMP I_ECX, TCSETA
1412 JE SHORT TC_SETA
1413 CMP I_ECX, TCSETAW
1414 JE SHORT TC_SETA
1415 CMP I_ECX, TCSETAF
1416 JE SHORT TC_SETAF
1417 CMP I_ECX, TCFLSH
1418 JE IOCTL_FLUSH
1419 CMP I_ECX, TCXONC
1420 JE IOCTL_XONC
1421 CMP I_ECX, TCSBRK
1422 JE IOCTL_SBRK
1423 CMP I_ECX, _TCGA
1424 JE SHORT TCS_GETA
1425 CMP I_ECX, _TCSANOW
1426 JE SHORT TCS_SETA
1427 CMP I_ECX, _TCSADRAIN
1428 JE SHORT TCS_SETA
1429 CMP I_ECX, _TCSAFLUSH
1430 JE SHORT TCS_SETAF
1431 CMP I_ECX, FIONREAD
1432 JE IOCTL_NREAD
1433 CMP I_ECX, FGETHTYPE
1434 JE IOCTL_HTYPE
1435 JMP EMX_EINVAL
1436
1437 TALIGN 4
1438TC_GETA: MOV EAX, I_EBX
1439 MOV ES, I_DS
1440 MOV EBX, I_EDX
1441 CALL TERMIO_GET
1442TC_RET: MOV I_EAX, EAX
1443 MOV I_ECX, ECX
1444 RET
1445
1446 TALIGN 4
1447TC_SETAF: MOV EAX, I_EBX
1448 CALL TERMIO_FLUSH
1449 OR EAX, EAX
1450 JNZ SHORT TC_RET
1451TC_SETA: MOV EAX, I_EBX
1452 MOV ES, I_DS
1453 MOV EBX, I_EDX
1454 CALL TERMIO_SET
1455 JMP SHORT TC_RET
1456
1457 TALIGN 4
1458TCS_GETA: MOV EAX, I_EBX
1459 MOV ES, I_DS
1460 MOV EBX, I_EDX
1461 CALL TERMIOS_GET
1462 JMP SHORT TC_RET
1463
1464 TALIGN 4
1465TCS_SETAF: MOV EAX, I_EBX
1466 CALL TERMIOS_FLUSH
1467 OR EAX, EAX
1468 JNZ SHORT TC_RET
1469TCS_SETA: MOV EAX, I_EBX
1470 MOV ES, I_DS
1471 MOV EBX, I_EDX
1472 CALL TERMIOS_SET
1473 JMP SHORT TC_RET
1474
1475;
1476; TCFLSH
1477;
1478 TALIGN 4
1479IOCTL_FLUSH: CMP I_EBX, 0 ; stdin?
1480 JNE EMX_EBADF
1481 CMP I_EDX, 0 ; Flush input queue
1482 JE SHORT IOCTL_FLUSH_1
1483 CMP I_EDX, 1 ; Flush output queue
1484 JE EMX_OK ; Not implemented -- ignore
1485 CMP I_EDX, 2 ; Flush input & output queues
1486 JNE EMX_EINVAL ; No -> error
1487IOCTL_FLUSH_1: CALL KBD_FLUSH
1488 JMP EMX_OK
1489
1490;
1491; TCSBRK (not implemented)
1492;
1493 TALIGN 4
1494IOCTL_SBRK: JMP EMX_OK
1495
1496;
1497; TCXCONC (not yet implemented)
1498;
1499 TALIGN 4
1500IOCTL_XONC: JMP EMX_OK
1501
1502 TALIGN 4
1503IOCTL_NREAD: CMP I_EBX, 0 ; stdin?
1504 JNE SHORT IOCTL_NREAD2 ; No -> check input status
1505 TEST STDIN_TERMIO.C_LFLAG, IDEFAULT OR ICANON ; termio?
1506 JNZ SHORT IOCTL_NREAD2 ; No -> check input status
1507 CALL STDIN_AVAIL
1508IOCTL_NREAD1: MOV EBX, I_EDX
1509 MOV ES, I_DS
1510 MOV ES:[EBX], EAX
1511 JMP EMX_OK
1512
1513IOCTL_NREAD2: MOV EBX, I_EBX ; Get file handle
1514 MOV AX, 4406H ; IOCTL: Check input status
1515 INT 21H
1516 JC SHORT IOCTL_ERR ; Error -> done
1517 OR AL, AL ; 00H=not ready, 0FFH=ready
1518 MOV EAX, 0 ; No characters ready
1519 JZ SHORT IOCTL_NREAD1 ; Not ready -> 0 characters
1520 INC EAX ; Ready -> 1 character
1521 JMP SHORT IOCTL_NREAD1
1522
1523IOCTL_ERR: MOV I_ECX, EAX
1524 MOV I_EAX, -1
1525 RET
1526
1527HT_FILE = 0
1528HT_UPIPE = 1
1529HT_NPIPE = 2
1530HT_DEV_OTHER = 3
1531HT_DEV_NUL = 4
1532HT_DEV_CON = 5
1533HT_DEV_CLK = 7
1534
1535 TALIGN 4
1536IOCTL_HTYPE: MOV AX, 4400H
1537 MOV EBX, I_EBX
1538 INT 21H
1539 JC SHORT HTYPE_ERR
1540 MOV ECX, HT_FILE
1541 TEST EDX, 80H
1542 JZ SHORT HTYPE_RET
1543 MOV ECX, HT_DEV_CON
1544 TEST EDX, 03H
1545 JNZ SHORT HTYPE_RET
1546 MOV ECX, HT_DEV_NUL
1547 TEST EDX, 04H
1548 JNZ SHORT HTYPE_RET
1549 MOV ECX, HT_DEV_CLK
1550 TEST EDX, 08H
1551 JNZ SHORT HTYPE_RET
1552 MOV ECX, HT_DEV_OTHER
1553HTYPE_RET: MOV EBX, I_EDX
1554 MOV ES, I_DS
1555 MOV ES:[EBX], ECX
1556 JMP EMX_OK
1557
1558HTYPE_ERR: MOV I_ECX, EAX
1559 MOV I_EAX, -1
1560 RET
1561
1562
1563; ----------------------------------------------------------------------------
1564; AX=7F15H: __alarm()
1565;
1566; Set alarm clock
1567;
1568; In: EDX Seconds
1569;
1570; Out: EAX Time remaining
1571;
1572; ----------------------------------------------------------------------------
1573
1574 TALIGN 4
1575SYS15: MOV EAX, I_EDX
1576 MOV ECX, 91
1577 MUL ECX ; Multiply by 18.2
1578 ADD EAX, 4
1579 ADC EDX, 0
1580 MOV ECX, 5
1581 CMP EDX, ECX ; Overflow?
1582 JAE SHORT ALARM_OV ; Yes -> use maximum value
1583 DIV ECX
1584ALARM_SET: MOV BX, DI
1585 MOV DX, TT_ALARM
1586 CALL SET_TIMER
1587 MOV I_EAX, 0
1588 JC SHORT SYS15_RET
1589 MOV ECX, 5
1590 MUL ECX ; Divide by 18.2
1591 MOV ECX, 91
1592 DIV ECX
1593 MOV I_EAX, EAX
1594SYS15_RET: RET
1595
1596ALARM_OV: MOV EAX, MAX_32 ; Use maximum value
1597 JMP SHORT ALARM_SET
1598
1599; ----------------------------------------------------------------------------
1600; AX=7F16H: Used internally for polling the keyboard
1601; ----------------------------------------------------------------------------
1602
1603 TALIGN 4
1604SYS16: TEST I_CS, 3 ; Called from user code?
1605 JNZ SYSCALL_ERROR ; Yes -> error
1606 MOV RM_AX, 7F16H
1607 CALL INT_RM
1608 RET
1609
1610; ----------------------------------------------------------------------------
1611; AX=7F17H: __sleep()
1612;
1613; Suspend process
1614;
1615; In: EDX Seconds
1616;
1617; Out: EAX Remaining seconds
1618;
1619; ----------------------------------------------------------------------------
1620
1621 TALIGN 4
1622SYS17: MOV EAX, I_EDX
1623 TEST EAX, EAX
1624 JZ SHORT SYS17_RET
1625 MOV ECX, 91
1626 MUL ECX ; Multiply by 18.2 = 91/5
1627 ADD EAX, 4
1628 ADC EDX, 0
1629 MOV ECX, 5
1630 CMP EDX, ECX ; Overflow?
1631 JAE SHORT SLEEP_OV
1632 DIV ECX
1633SLEEP_DO: MOV BX, DI
1634 CALL SLEEP
1635 MOV ECX, 5
1636 MUL ECX ; Divide by 18.2
1637 MOV ECX, 91
1638 DIV ECX
1639SYS17_RET: MOV I_EAX, EAX
1640 RET
1641
1642SLEEP_OV: MOV EAX, MAX_32 ; Use maximum value
1643 JMP SHORT SLEEP_DO
1644
1645; ----------------------------------------------------------------------------
1646; AX=7F18H: __chsize()
1647;
1648; Change file size
1649;
1650; In: EBX File handle
1651; EDX File size
1652;
1653; Out: CY Error
1654; EAX errno (CY)
1655;
1656; ----------------------------------------------------------------------------
1657
1658 TALIGN 4
1659SYS18: MOV EBX, I_EBX ; File handle
1660 MOV EDX, I_EDX ; Distance
1661 MOV AL, 0 ; SEEK_SET
1662 MOV AH, 42H ; Move file pointer
1663 INT 21H
1664 JC SHORT SYS18_RET
1665 MOV EBX, I_EBX ; File handle
1666 MOV ECX, 0 ; Number of bytes
1667 MOV EDX, 0 ; Buffer
1668 MOV AH, 40H ; Write handle
1669 INT 21H
1670 JC SHORT SYS18_RET
1671 XOR EAX, EAX
1672SYS18_RET: MOV I_EAX, EAX
1673 RET
1674
1675
1676; ----------------------------------------------------------------------------
1677; AX=7F19H: __fcntl()
1678;
1679; Unix-like file control
1680;
1681; In: EBX File handle
1682; ECX Request code
1683; EDX Argument
1684;
1685; Out: EAX Return value
1686; ECX errno
1687;
1688; ----------------------------------------------------------------------------
1689
1690 TALIGN 4
1691 ASSUME DI:PTR PROCESS
1692SYS19: CMP I_ECX, F_SETFL
1693 JE SHORT FCNTL_SETFL
1694 CMP I_ECX, F_SETFD
1695 JE SHORT FCNTL_SETFD
1696 CMP I_ECX, F_GETFD
1697 JE SHORT FCNTL_GETFD
1698 CMP I_ECX, F_GETFL
1699 JE FCNTL_GETFL
1700EMX_EINVAL: MOV I_ECX, EINVAL
1701 MOV I_EAX, -1
1702 RET
1703
1704 TALIGN 4
1705FCNTL_GETFD: MOV BX, WORD PTR I_EBX
1706 CMP BX, MAX_FILES
1707 JAE EMX_EBADF
1708 XOR EAX, EAX
1709 SHL BX, 1
1710 TEST [DI].P_HFLAGS[BX], HF_NOINHERIT
1711 JZ SHORT GETFD_1
1712 OR EAX, 1 ; FD_CLOEXEC
1713GETFD_1: MOV I_EAX, EAX
1714 MOV I_ECX, 0
1715 RET
1716
1717 TALIGN 4
1718FCNTL_SETFD: MOV BX, WORD PTR I_EBX
1719 CMP BX, MAX_FILES
1720 JAE EMX_EBADF
1721 SHL BX, 1
1722 AND [DI].P_HFLAGS[BX], NOT HF_NOINHERIT
1723 TEST I_EDX, 1 ; FD_CLOEXEC
1724 JZ SHORT SETFD_1
1725 OR [DI].P_HFLAGS[BX], HF_NOINHERIT
1726SETFD_1: JMP SHORT EMX_OK
1727
1728 TALIGN 4
1729FCNTL_SETFL: MOV BX, WORD PTR I_EBX
1730 CMP BX, MAX_FILES
1731 JAE SHORT EMX_EBADF
1732 SHL BX, 1
1733 MOV EAX, I_EDX
1734 TEST EAX, NOT (O_NDELAY OR O_APPEND)
1735 JNZ SHORT EMX_EINVAL
1736 .ERRE O_NDELAY EQ HF_NDELAY
1737 .ERRE O_APPEND EQ HF_APPEND
1738 AND [DI].P_HFLAGS[BX], NOT (HF_NDELAY OR HF_APPEND)
1739 OR [DI].P_HFLAGS[BX], AX
1740 CMP I_EBX, 0 ; stdin?
1741 JNE SHORT EMX_OK
1742 MOV STDIN_FL, EAX
1743 TALIGN 4
1744EMX_OK: MOV I_ECX, 0
1745 MOV I_EAX, 0
1746 RET
1747
1748 TALIGN 4
1749FCNTL_GETFL: MOV BX, WORD PTR I_EBX
1750 CMP BX, MAX_FILES
1751 JAE SHORT EMX_EBADF
1752 SHL BX, 1
1753 XOR EAX, EAX
1754 MOV AX, [DI].P_HFLAGS[BX]
1755 .ERRE O_NDELAY EQ HF_NDELAY
1756 .ERRE O_APPEND EQ HF_APPEND
1757 AND AX, HF_NDELAY OR HF_APPEND
1758 MOV I_EAX, EAX
1759 MOV I_ECX, 0
1760 RET
1761
1762 TALIGN 4
1763EMX_EBADF: MOV I_ECX, EBADF
1764 MOV I_EAX, -1
1765 RET
1766 ASSUME DI:NOTHING
1767
1768; ----------------------------------------------------------------------------
1769; AX=7F1AH: __pipe()
1770;
1771; Create unnamed pipe
1772;
1773; In: ECX Size of pipe
1774; EDX Pointer to storage for two handles (two DWORDs)
1775;
1776; Out: EAX 0 (success) or -1 (failure)
1777; ECX errno
1778;
1779; ----------------------------------------------------------------------------
1780
1781 TALIGN 4
1782SYS1A: MOV I_ECX, ENOSYS
1783 MOV I_EAX, -1
1784 RET
1785
1786; ----------------------------------------------------------------------------
1787; AX=7F1BH: __fsync()
1788;
1789; Update file system
1790;
1791; In: EBX File handle
1792;
1793; Out: EAX 0 (success) or -1 (failure)
1794; ECX errno
1795;
1796; ----------------------------------------------------------------------------
1797
1798 TALIGN 4
1799SYS1B: MOV I_ECX, ENOSYS
1800 MOV I_EAX, -1
1801 RET
1802
1803; ----------------------------------------------------------------------------
1804; AX=7F1CH: __fork()
1805;
1806; Duplicate process
1807;
1808;
1809; Out: EAX Process ID or 0 (in new process) or -1 (failure)
1810; ECX errno (0 if successful)
1811;
1812; ----------------------------------------------------------------------------
1813 TALIGN 4
1814SYS1C: MOV I_ECX, ENOSYS
1815 MOV I_EAX, -1
1816 RET
1817
1818; ----------------------------------------------------------------------------
1819; AX=7F1DH: __scrsize()
1820;
1821; Get number of rows and columns
1822;
1823; In: EDX Pointer to structure
1824;
1825; Out: --
1826;
1827; ----------------------------------------------------------------------------
1828
1829 TALIGN 4
1830SYS1D: MOV EBX, I_EDX
1831 MOV ES, I_DS
1832 MOVZX EAX, VWIDTH
1833 MOV DWORD PTR ES:[EBX+0], EAX
1834 MOVZX EAX, VHEIGHT
1835 MOV DWORD PTR ES:[EBX+4], EAX
1836 RET
1837
1838; ----------------------------------------------------------------------------
1839; AX=7F1EH: __select()
1840;
1841; Synchronous I/O multiplexing
1842;
1843; In: EDX pointer to structure
1844;
1845; Out: EAX 0 (timeout), > 0 (ready) or -1 (failure)
1846; ECX errno (0 if successful)
1847;
1848; ----------------------------------------------------------------------------
1849
1850 TALIGN 4
1851 ASSUME DI:PTR PROCESS
1852SYS1E: AND [DI].P_FLAGS, NOT PF_SLEEP_FLAG ; Clear counter flag
1853 MOV SEL_COUNT, 0 ; No ready handles
1854 MOV ESI, I_EDX ; Get pointer to structure
1855 MOV ES, I_DS ; and segment register
1856 ASSUME ESI:NEAR32 PTR SELECT_ARGS
1857 MOV EBX, ES:[ESI].SELA_TIMEOUT ; Get timeout pointer
1858 TEST EBX, EBX ; NULL pointer?
1859 JZ SHORT SELECT_LOOP ; Yes -> indefinite wait
1860 ASSUME EBX:NEAR32 PTR TIMEVAL
1861 MOV EAX, ES:[EBX].TV_USEC ; Get microseconds
1862 XOR EDX, EDX
1863 MOV ECX, 54945
1864 DIV ECX ; Convert to timer ticks
1865 PUSH EAX ; Save ticks for microseconds
1866 MOV EAX, ES:[EBX].TV_SEC ; Get seconds
1867 ASSUME EBX:NOTHING
1868 MOV ECX, 91
1869 MUL ECX ; Multiply by 18.2 = 91/5
1870 ADD EAX, 4
1871 ADC EDX, 0
1872 MOV ECX, 5
1873 CMP EDX, ECX
1874 JAE SHORT SELECT_OV1
1875 DIV ECX
1876 POP ECX ; Ticks for microseconds
1877 ADD EAX, ECX ; Total number of ticks
1878 JC EMX_EINVAL ; Overflow -> error
1879 JZ SHORT SELECT_ONCE ; Zero -> return after one loop
1880 MOV DX, TT_SLEEP ; Set `sleep' timer
1881 MOV BX, DI ; Process table entry
1882 CALL SET_TIMER
1883 JC EMX_EINVAL ; Table overflow -> error
1884 JMP SHORT SELECT_LOOP ; Start loop
1885
1886SELECT_OV1: POP ECX ; Ticks for microseconds
1887 JMP EMX_EINVAL ; Error
1888
1889SELECT_ONCE: OR [DI].P_FLAGS, PF_SLEEP_FLAG ; Return after first loop
1890 ASSUME DI:NOTHING
1891 LEA DI, SEL_RBITS ; Clear all bits in the
1892 MOV_ES_DS ; bitmap of ready handles
1893 MOV CX, FD_SETSIZE/8
1894 XOR AL, AL
1895 REP STOSB
1896 MOV ES, I_DS
1897;
1898; This is the main loop
1899;
1900SELECT_LOOP: MOV BX, PROCESS_PTR
1901 ASSUME BX:PTR PROCESS
1902 MOV EAX, [BX].P_SIG_BLOCKED ; Compute set of pending,
1903 NOT EAX ; unblocked signals
1904 AND EAX, [BX].P_SIG_PENDING
1905 ASSUME BX:NOTHING
1906;
1907; TODO: Deliver signals set to SIG_DFL now
1908; TODO: Ignore signals set to SIG_IGN
1909;
1910 JNZ SELECT_INTR ; Signal -> return EINTR
1911 MOV EDI, ES:[ESI].SELA_READFDS ; Get readfds pointer
1912 TEST EDI, EDI ; NULL pointer?
1913 JZ SELECT_TIME ; Yes -> wait until timeout
1914 XOR EBX, EBX ; Start with handle 0
1915SELECT_POLL: CMP EBX, ES:[ESI].SELA_NFDS ; All handles checked?
1916 JAE SELECT_CHECK ; Yes -> any ready handles?
1917 BT DWORD PTR ES:[EDI], EBX ; Handle in readfds bitmap?
1918 JNC SELECT_NEXT ; No -> next handle
1919 CMP EBX, 0 ; stdin?
1920 JNZ SHORT SELECT_TEST ; No -> check input status
1921 TEST STDIN_TERMIO.C_LFLAG, IDEFAULT ; termio?
1922 JNZ SHORT SELECT_TEST ; No -> check input status
1923 CALL STDIN_AVAIL ; Get number of available chars
1924 TEST EAX, EAX ; Any characters available?
1925 JNZ SHORT SELECT_HIT ; Yes -> handle ready
1926 JMP SHORT SELECT_NEXT ; Next handle
1927
1928SELECT_TEST: PUSH EBX
1929 PUSH ESI
1930 PUSH EDI
1931 MOV AX, 4406H ; IOCTL: Check input status
1932 INT 21H
1933 POP EDI
1934 POP ESI
1935 POP EBX
1936 JC SELECT_ERR ; Error -> done
1937 TEST AL, AL ; 00H=not ready, 0FFH=ready
1938 JZ SHORT SELECT_NEXT ; Not ready -> next handle
1939SELECT_HIT: INC SEL_COUNT ; Increment # of ready handles
1940 BTS DWORD PTR SEL_RBITS, EBX ; Set bit in bitmap
1941SELECT_NEXT: INC EBX ; Next handle
1942 JMP SELECT_POLL ; Check next handle
1943
1944;
1945; Having looped though the handles, check if a handle is ready
1946;
1947SELECT_CHECK: CMP SEL_COUNT, 0 ; Are there ready handles?
1948 JNE SHORT SELECT_READY ; Yes -> success
1949SELECT_TIME: MOV EBX, ES:[ESI].SELA_TIMEOUT ; Get pointer to timeout
1950 TEST EBX, EBX ; NULL pointer?
1951 JZ SELECT_LOOP ; Yes -> indefinite wait
1952 MOV BX, PROCESS_PTR ; Process table entry
1953 TEST (PROCESS PTR [BX]).P_FLAGS, PF_SLEEP_FLAG ; Timer down?
1954 JZ SELECT_LOOP ; No -> check handles again
1955;
1956; Time out, clear all sets
1957;
1958 MOV EDI, ES:[ESI].SELA_READFDS
1959 CALL CLEAR_FDSET
1960 MOV EDI, ES:[ESI].SELA_WRITEFDS
1961 CALL CLEAR_FDSET
1962 MOV EDI, ES:[ESI].SELA_EXCEPTFDS
1963 CALL CLEAR_FDSET
1964 MOV I_EAX, 0 ; Time out
1965 MOV I_ECX, 0 ; No error
1966 JMP SELECT_RET ; Done
1967
1968;
1969; At least one handle is ready
1970;
1971SELECT_READY: MOVZX EAX, SEL_COUNT ; Return number of ready
1972 MOV I_EAX, EAX ; handles
1973 MOV I_ECX, 0 ; No error
1974 PUSH ESI ; Save pointer to structure
1975 LEA ESI, SEL_RBITS ; Copy bitmap of ready handles
1976 MOV ECX, FD_SETSIZE/8 ; to readfds
1977 REP MOVS BYTE PTR ES:[EDI], BYTE PTR DS:[ESI]
1978 POP ESI ; Restore pointer to structure
1979 MOV EDI, ES:[ESI].SELA_WRITEFDS ; Get writefds pointer
1980 CALL CLEAR_FDSET
1981 MOV EDI, ES:[ESI].SELA_EXCEPTFDS ; Get exceptfds pointer
1982 CALL CLEAR_FDSET
1983SELECT_RET: RET ; Done
1984
1985;
1986; A signal occured while waiting in select(). Return EINTR and raise
1987; the signal.
1988;
1989SELECT_INTR: MOV EAX, EINTR
1990
1991SELECT_ERR: MOV I_ECX, EAX ; Return errno in ECX
1992 MOV I_EAX, -1 ; Error
1993 JMP SHORT SELECT_RET ; Done
1994
1995;
1996; Clear a fd_set object pointed to by ES:EDI if EDI is not NULL
1997;
1998 ALIGN 4
1999CLEAR_FDSET PROC NEAR
2000 TEST EDI, EDI
2001 JZ SHORT FIN
2002 MOV ECX, FD_SETSIZE/8
2003 XOR AL, AL
2004 MOV ECX, FD_SETSIZE/8
2005 REP STOS BYTE PTR ES:[EDI]
2006FIN: RET
2007CLEAR_FDSET ENDP
2008
2009 ASSUME ESI:NOTHING
2010
2011; ----------------------------------------------------------------------------
2012; AX=7F1FH: __syserrno()
2013;
2014; Return DOS error number for last syscall
2015;
2016; Out: EAX error number
2017;
2018; ----------------------------------------------------------------------------
2019
2020 TALIGN 4
2021SYS1F: MOV I_EAX, 0
2022 RET
2023
2024; ----------------------------------------------------------------------------
2025; AX=7F20H __stat()
2026;
2027; Get information about a path name
2028;
2029; In: EDX path name
2030; EDI pointer to structure
2031;
2032; Out: EAX 0 (ok), -1 (error)
2033; ECX errno (0 if successful)
2034;
2035; ----------------------------------------------------------------------------
2036 TALIGN 4
2037 ASSUME EDI:NEAR32 PTR STAT
2038SYS20: MOV ESI, I_EDX ; Pointer to path name
2039 MOV ES, I_DS
2040;
2041; Return ENOENT if the path name contains wildcard characters
2042;
2043 TALIGN 4
2044NSTAT_WILD: LODS BYTE PTR ES:[ESI]
2045 TEST AL, AL
2046 JZ SHORT NSTAT_NOWILD
2047 CMP AL, "?"
2048 JE SHORT NSTAT_FAILURE1
2049 CMP AL, "*"
2050 JNE SHORT NSTAT_WILD
2051NSTAT_FAILURE1: JMP NSTAT_FAILURE
2052
2053NSTAT_NOWILD: MOV EDX, I_EDX ; Pointer to path name
2054 MOV ESI, I_ESP ; Allocate FIND_BUF in user
2055 SUB ESI, SIZE FIND_BUF ; stack (same segment as path!)
2056 ASSUME ESI:NEAR32 PTR FIND_BUF
2057 PUSH DS
2058 MOV DS, I_DS
2059 MOV CX, 16H ; Dir & system & hidden
2060 MOV AH, 4EH ; Find first file
2061 INT 21H
2062 POP DS
2063 JC NSTAT_10 ; Error -> root directory?
2064 MOV EDI, I_EDI ; Pointer to structure
2065 MOV ES, I_DS ; Use ES for user data segment
2066 MOV EAX, S_IFREG ; File
2067 TEST ES:[ESI].FIND_ATTR, 10H ; Is it a directory?
2068 JZ SHORT NSTAT_1 ; No -> it's a file
2069 MOV ES:[ESI].FIND_SIZE, 0 ; The size of a directory is 0
2070 MOV EAX, S_IFDIR OR ((S_IREAD+S_IWRITE+S_IEXEC) SHR 6) * 111Q
2071 JMP SHORT NSTAT_2
2072 TALIGN 4
2073NSTAT_1: OR EAX, (S_IREAD SHR 6) * 111Q ; Read-only access
2074 TEST ES:[ESI].FIND_ATTR, 01H ; Ready-only attribute set?
2075 JNZ SHORT NSTAT_2 ; Yes -> skip
2076 OR EAX, (S_IWRITE SHR 6) * 111Q ; Read-write access
2077NSTAT_2: MOV ES:[EDI].ST_MODE, EAX ; Set mode
2078 MOVZX EAX, ES:[ESI].FIND_ATTR ; Get attributes
2079 MOV ES:[EDI].ST_ATTR, EAX ; and store them
2080 MOV EAX, ES:[ESI].FIND_SIZE ; Get size
2081 MOV ES:[EDI].ST_SIZE, EAX ; and store it
2082 MOV CX, ES:[ESI].FIND_TIME ; Get time
2083 MOV DX, ES:[ESI].FIND_DATE ; and date
2084 CALL PACKED_2_UNIX ; and convert them to time_t
2085NSTAT_MORE: MOV ES:[EDI].ST_ATIME, EAX ; Time of last access
2086 MOV ES:[EDI].ST_MTIME, EAX ; Time of last modification
2087 MOV ES:[EDI].ST_CTIME, EAX ; Time of creation
2088 MOV ES:[EDI].ST_NLINK, 1 ; One link
2089 MOV ES:[EDI].ST_UID, 0 ; root
2090 MOV ES:[EDI].ST_GID, 0 ; root
2091 MOV ES:[EDI].ST_DEV, 0 ; Device numbers not supported
2092 MOV ES:[EDI].ST_RDEV, 0 ; Device numbers not supported
2093 MOV ES:[EDI].ST_RESERVED, 0 ; Nomen est omen
2094 MOV EAX, INO_NUMBER ; Mock inode number
2095 MOV ES:[EDI].ST_INO, EAX
2096 INC INO_NUMBER
2097 JNZ SHORT NSTAT_INO_1
2098 INC INO_NUMBER
2099NSTAT_INO_1: JMP EMX_OK ; Done
2100
2101;
2102; Not found -- check for root directory
2103;
2104; Get current working directory and save it. Then try to change to the
2105; "directory" given as argument to __stat(). If successful, it's the
2106; root directory: set the structure appropriately and restore the
2107; previous working directory. Otherwise, the file/directory does not
2108; exist (or it's a device -- which is not supported by this implementation
2109; of stat).
2110;
2111 TALIGN 4
2112NSTAT_10: MOV EBX, I_EDX
2113 MOV ES, I_DS
2114 MOV AL, ES:[EBX]
2115 CALL UPPER
2116 CMP AL, "A"
2117 JB SHORT NSTAT_11
2118 CMP AL, "Z"
2119 JA SHORT NSTAT_11
2120 CMP BYTE PTR ES:[EBX+1], ":"
2121 JE SHORT NSTAT_12
2122NSTAT_11: MOV AH, 19H
2123 INT 21H
2124 ADD AL, "A"
2125NSTAT_12: MOV STAT_CWD, AL
2126 SUB AL, "A" - 1
2127 MOV DL, AL
2128 LEA ESI, STAT_CWD + 3
2129 MOV AH, 47H
2130 INT 21H
2131 JC SHORT NSTAT_FAILURE
2132 PUSH DS
2133 MOV EDX, I_EDX
2134 MOV DS, I_DS
2135 MOV AH, 3BH
2136 INT 21H
2137 POP DS
2138 JC SHORT NSTAT_FAILURE
2139 LEA EDX, STAT_CWD
2140 MOV AH, 3BH
2141 INT 21H
2142 MOV EDI, I_EDI
2143 MOV ES, I_DS
2144 MOV ES:[EDI].ST_MODE, S_IFDIR+((S_IREAD+S_IWRITE+S_IEXEC) SHR 6)*111Q
2145 MOV ES:[EDI].ST_ATTR, 0 ; Look here to find out about
2146 ; root directory (not 10H!)
2147 MOV ES:[EDI].ST_SIZE, 0
2148 XOR EAX, EAX
2149 JMP NSTAT_MORE
2150
2151 TALIGN 4
2152NSTAT_FAILURE: MOV I_EAX, -1
2153 MOV I_ECX, ENOENT
2154 RET
2155
2156 ASSUME ESI:NOTHING
2157 ASSUME EDI:NOTHING
2158
2159; ----------------------------------------------------------------------------
2160; AX=7F21H __fstat()
2161;
2162; Get information about an open file
2163;
2164; In: EBX file handle
2165; EDI pointer to structure
2166;
2167; Out: EAX 0 (ok), -1 (error)
2168; ECX errno (0 if successful)
2169;
2170; ----------------------------------------------------------------------------
2171 TALIGN 4
2172 ASSUME EDI:NEAR32 PTR STAT
2173SYS21: MOV EBX, I_EBX
2174 MOV AX, 4400H
2175 INT 21H
2176 JC FSTAT_ERROR
2177 MOV EDI, I_EDI
2178 MOV ES, I_DS
2179 TEST DL, 80H ; Device?
2180 JNZ FSTAT_DEV
2181 MOV ES:[EDI].ST_MODE, S_IFREG
2182 MOV ES:[EDI].ST_ATTR, 0
2183 MOV ES:[EDI].ST_RESERVED, 0
2184 MOV AX, 5700H
2185 INT 21H
2186 JC FSTAT_ERROR
2187 CALL PACKED_2_UNIX
2188 MOV ES:[EDI].ST_ATIME, EAX
2189 MOV ES:[EDI].ST_MTIME, EAX
2190 MOV ES:[EDI].ST_CTIME, EAX
2191 MOV AX, 4201H
2192 MOV EDX, 0
2193 INT 21H
2194 JC FSTAT_ERROR
2195 MOV ESI, EAX
2196 MOV AX, 4202H
2197 MOV EDX, 0
2198 INT 21H
2199 JC FSTAT_ERROR
2200 MOV ES:[EDI].ST_SIZE, EAX
2201 MOV AX, 4200H
2202 MOV EDX, ESI
2203 INT 21H
2204 JC FSTAT_ERROR
2205 JMP SHORT FSTAT_MORE
2206
2207 TALIGN 4
2208FSTAT_DEV: MOV ES:[EDI].ST_MODE, S_IFCHR
2209 MOV ES:[EDI].ST_SIZE, 0
2210 MOV ES:[EDI].ST_ATIME, 0
2211 MOV ES:[EDI].ST_MTIME, 0
2212 MOV ES:[EDI].ST_CTIME, 0
2213FSTAT_MORE: MOV EAX, INO_NUMBER
2214 MOV ES:[EDI].ST_INO, EAX
2215 INC INO_NUMBER
2216 JNZ SHORT FSTAT_INO_1
2217 INC INO_NUMBER
2218FSTAT_INO_1: MOV ES:[EDI].ST_UID, 0
2219 MOV ES:[EDI].ST_GID, 0
2220 MOV ES:[EDI].ST_NLINK, 1
2221 MOV ES:[EDI].ST_DEV, 0
2222 MOV ES:[EDI].ST_RDEV, 0
2223 OR ES:[EDI].ST_MODE, ((S_IREAD+S_IWRITE) SHR 6) * 111Q
2224 JMP EMX_OK
2225
2226FSTAT_ERROR: MOV I_EAX, -1
2227 MOV I_ECX, EAX
2228 RET
2229
2230 ASSUME EDI:NOTHING
2231
2232
2233; ----------------------------------------------------------------------------
2234; AX=7F23H __filesys()
2235;
2236; Get name of file-system driver
2237;
2238; In: EDX pointer to drive name
2239; EDI pointer to output buffer
2240; ECX size of output buffer
2241;
2242; Out: EAX 0 (ok) or -1 (error)
2243; ECX errno (0 if successful)
2244;
2245; ----------------------------------------------------------------------------
2246 TALIGN 4
2247SYS23: MOV EBX, I_EDX
2248 MOV ES, I_DS
2249 MOV AL, ES:[EBX+0]
2250 CALL UPPER
2251 CMP AL, "A"
2252 JB SHORT FILESYS_INVALID
2253 CMP AL, "Z"
2254 JA SHORT FILESYS_INVALID
2255 CMP BYTE PTR ES:[EBX+1], ":"
2256 JNE SHORT FILESYS_INVALID
2257 CMP BYTE PTR ES:[EBX+2], 0
2258 JNE SHORT FILESYS_INVALID
2259 CMP I_ECX, 4
2260 JB SHORT FILESYS_2BIG
2261 SUB AL, "A"-1
2262 MOV BL, AL
2263 MOV AX, 4409H
2264 INT 21H
2265 JC SHORT FILESYS_ERROR
2266 LEA ESI, $FAT
2267 TEST DX, 1 SHL 12
2268 JZ SHORT FILESYS_1
2269 LEA ESI, $LAN
2270FILESYS_1: MOV ECX, 4
2271 MOV EDI, I_EDI
2272 REP MOVS BYTE PTR ES:[EDI], BYTE PTR DS:[ESI]
2273 JMP EMX_OK
2274
2275FILESYS_2BIG: MOV EAX, E2BIG
2276 JMP SHORT FILESYS_ERROR
2277
2278FILESYS_INVALID:MOV EAX, EINVAL
2279FILESYS_ERROR: MOV I_EAX, -1
2280 MOV I_ECX, EAX
2281 RET
2282
2283; ----------------------------------------------------------------------------
2284; AX=7F24H __utimes()
2285;
2286; Set access and modification time of a file
2287;
2288; In: EDX pointer to path name
2289; ESI pointer to array of structures
2290;
2291; Out: EAX 0 (ok) or -1 (error)
2292; ECX errno (0 if successful)
2293;
2294; ----------------------------------------------------------------------------
2295 TALIGN 4
2296SYS24: PUSH PROCESS_PTR
2297 MOV PROCESS_PTR, NO_PROCESS
2298 PUSH DS
2299 MOV EDX, I_EDX
2300 MOV DS, I_DS
2301 ASSUME DS:NOTHING
2302 MOV AX, 3D11H
2303 INT 21H
2304 POP DS
2305 ASSUME DS:SV_DATA
2306 JC SHORT UTIMES_ERROR
2307 MOV EBX, EAX
2308 MOV ESI, I_ESI
2309 MOV ES, I_DS
2310 MOV EAX, ES:[ESI+8] ; Modification time
2311 CALL UNIX_2_PACKED
2312 MOV AX, 5701H
2313 INT 21H
2314 JC SHORT UTIMES_1
2315 MOV AH, 3EH
2316 INT 21H
2317 JC SHORT UTIMES_ERROR
2318 MOV I_EAX, 0
2319 MOV I_ECX, 0
2320UTIMES_RET: POP PROCESS_PTR
2321 RET
2322
2323UTIMES_1: PUSH EAX
2324 MOV AH, 3EH
2325 INT 21H
2326 POP EAX
2327UTIMES_ERROR: MOV I_EAX, -1
2328 MOV I_ECX, EAX
2329 JMP SHORT UTIMES_RET
2330
2331
2332; ----------------------------------------------------------------------------
2333; AX=7F25H: __ftruncate()
2334;
2335; Truncate a file
2336;
2337; In: EBX File handle
2338; EDX File size
2339;
2340; Out: EAX 0 (ok), -1 (error)
2341; ECX errno
2342;
2343; ----------------------------------------------------------------------------
2344
2345 TALIGN 4
2346SYS25: MOV EBX, I_EBX ; File handle
2347 MOV EDX, 0 ; Distance
2348 MOV AL, 2 ; SEEK_END
2349 MOV AH, 42H ; Move file pointer
2350 INT 21H
2351 JC SHORT SYS25_ERR ; Error ->
2352 CMP I_EDX, EAX ; Truncating?
2353 JNB EMX_OK ; No -> ignore request, OK
2354 MOV EBX, I_EBX ; File handle
2355 MOV EDX, I_EDX ; Distance
2356 MOV AL, 0 ; SEEK_SET
2357 MOV AH, 42H ; Move file pointer
2358 INT 21H
2359 JC SHORT SYS25_ERR ; Error ->
2360 MOV EBX, I_EBX ; File handle
2361 MOV ECX, 0 ; Number of bytes
2362 MOV EDX, 0 ; Buffer
2363 MOV AH, 40H ; Write handle
2364 INT 21H
2365 JNC EMX_OK
2366SYS25_ERR: MOV I_ECX, EAX
2367 MOV I_EAX, -1
2368 RET
2369
2370; ----------------------------------------------------------------------------
2371; AX=7F26H: __clock()
2372;
2373; Processor time
2374;
2375; Out: EAX timer ticks of processor time used, low-order 32 bits
2376; EDX high-order 32 bits
2377;
2378; ----------------------------------------------------------------------------
2379 TALIGN 4
2380SYS26: MOV EAX, CLOCK_HI
2381 MOV EBX, CLOCK_LO
2382 CMP EAX, CLOCK_HI
2383 JNE SHORT SYS26
2384 MOV ECX, 500
2385 MUL ECX
2386 XCHG EAX, EBX
2387 MUL ECX ; Multiply by 100 / 18.2
2388 ADD EDX, EBX
2389 PUSH EAX
2390 MOV EAX, EDX
2391 XOR EDX, EDX
2392 MOV ECX, 91
2393 DIV ECX
2394 MOV I_EDX, EAX
2395 POP EAX
2396 DIV ECX
2397 MOV I_EAX, EAX
2398 RET
2399
2400; ----------------------------------------------------------------------------
2401; AX=7F27H: __ftime()
2402;
2403; Get current time
2404;
2405; In: EDX pointer to structure
2406;
2407; ----------------------------------------------------------------------------
2408 TALIGN 4
2409SYS27: MOV EDI, I_EDX
2410 MOV ES, I_DS
2411 CALL DO_FTIME
2412 RET
2413
2414
2415; ----------------------------------------------------------------------------
2416; AX=7F28H: __umask()
2417;
2418; Set file permission mask
2419;
2420; In: EDX file permission mask
2421;
2422; Out: EAX previous file permission mask
2423;
2424; ----------------------------------------------------------------------------
2425 TALIGN 4
2426 ASSUME DI:PTR PROCESS
2427SYS28: MOV AX, WORD PTR I_EDX
2428 XCHG AX, [DI].P_UMASK
2429 MOVZX EAX, AX
2430 MOV I_EAX, EAX
2431 RET
2432
2433 ASSUME DI:NOTHING
2434
2435; ----------------------------------------------------------------------------
2436; AX=7F29H: __getppid()
2437;
2438; Get parent process ID
2439;
2440; Out: EAX parent process ID
2441;
2442; ----------------------------------------------------------------------------
2443 TALIGN 4
2444 ASSUME DI:PTR PROCESS
2445SYS29: MOV EAX, [DI].P_PPID
2446 MOV I_EAX, EAX
2447 RET
2448
2449 ASSUME DI:NOTHING
2450
2451; ----------------------------------------------------------------------------
2452; AX=7F2AH: __nls_memupr()
2453;
2454; Convert buffer to upper case
2455;
2456; In: EDX pointer to buffer
2457; ECX size of buffer
2458;
2459; ----------------------------------------------------------------------------
2460 TALIGN 4
2461SYS2A: MOV AX, I_DS
2462 MOV ESI, I_EDX
2463 MOV EDI, OFFSET_1
2464 MOV ECX, I_ECX
2465 MOV RM_DX, DI ; Offset of buffer
2466 MOV RM_CX, CX
2467 CALL MOVE_TO_RM
2468 MOV RM_AX, 7F2AH
2469 CALL INT_RM
2470 MOV AX, I_DS
2471 MOV EDI, I_EDX
2472 MOV ECX, I_ECX
2473 CALL MOVE_FROM_RM
2474 RET
2475
2476
2477
2478; ----------------------------------------------------------------------------
2479; AX=7F2BH: __open
2480;
2481; Open file
2482;
2483; In: EDX pointer to file name
2484; ECX flags
2485;
2486; Out: EAX handle or -1
2487; ECX errno (0 if successful)
2488;
2489; ----------------------------------------------------------------------------
2490;
2491; Replace "/dev/null" with "nul"
2492;
2493SYS2B_NUL: MOV I_EDX, OFFSET $NUL ; Use "nul" instead
2494 MOV SI, DS
2495 JMP SHORT SYS2B_1
2496
2497;
2498; Replace "/dev/tty" with "con"
2499;
2500SYS2B_CON: MOV I_EDX, OFFSET $CON ; Use "con" instead
2501 MOV SI, DS
2502 JMP SHORT SYS2B_1
2503
2504;
2505; __open()
2506;
2507 TALIGN 4
2508SYS2B: LEA ESI, $DEVNULL
2509 MOV EDI, I_EDX
2510 MOV ES, I_DS
2511 CALL STRCMP ; "/dev/null"?
2512 JE SHORT SYS2B_NUL ; Yes -> use "nul"
2513 LEA ESI, $DEVTTY
2514 MOV EDI, I_EDX
2515 CALL STRCMP ; "/dev/tty"?
2516 JE SHORT SYS2B_CON ; Yes -> use "con"
2517 MOV SI, I_DS
2518SYS2B_1: MOV EDX, I_EDX ; File name
2519 MOV AL, BYTE PTR I_ECX[0] ; Open mode
2520 MOV AH, 3DH
2521 PUSH DS
2522 MOV DS, SI
2523 INT 21H
2524 POP DS
2525 JC SHORT SYS2B_FAILED
2526;
2527; File exists
2528;
2529 MOV EDX, I_ECX
2530 AND EDX, 30000H ; O_CREAT|O_EXCL
2531 CMP EDX, 30000H ; O_CREAT and O_EXCL set?
2532 JE SYS2B_EXFAIL ; Yes -> fail
2533 MOV I_EAX, EAX ; Save the handle
2534SYS2B_OK: TEST I_ECX, 40000H ; O_TRUNC set?
2535 JZ SHORT SYS2B_SUCCESS ; No -> don't truncate file
2536 MOV EBX, EAX ; File handle
2537 XOR EDX, EDX ; Distance = 0
2538 MOV AL, 0 ; SEEK_SET
2539 MOV AH, 42H ; Move file pointer
2540 INT 21H
2541 JC SHORT SYS2B_SUCCESS ; Ignore error (device!)
2542 MOV EBX, I_EAX ; File handle
2543 MOV ECX, 0 ; Number of bytes
2544 MOV EDX, 0 ; Buffer
2545 MOV AH, 40H ; Write handle
2546 INT 21H ; Ignore error (device!)
2547;
2548; Opening the file succeeded. Set the handle flags.
2549;
2550SYS2B_SUCCESS: TEST I_ECX, 80000H ; O_NOINHERIT?
2551 JZ SHORT SYS2B_RET
2552 MOV BX, PROCESS_PTR
2553 CMP BX, NO_PROCESS
2554 JE SHORT SYS2B_RET
2555 ASSUME BX:PTR PROCESS
2556 MOV SI, WORD PTR I_EAX
2557 SHL SI, 1
2558 OR [BX].P_HFLAGS[SI], HF_NOINHERIT
2559 ASSUME BX:NOTHING
2560SYS2B_RET: MOV I_ECX, 0 ; Success
2561 RET
2562
2563;
2564; Opening an existing file failed.
2565;
2566SYS2B_FAILED: CMP EAX, ENOENT ; No such file?
2567 JNE SHORT SYS2B_ERR ; No -> fail
2568 TEST I_ECX, 10000H ; O_CREAT?
2569 JZ SHORT SYS2B_ERR ; No -> fail
2570;
2571; Try to create the file
2572;
2573 MOV EDX, I_EDX ; File name
2574 MOVZX CX, BYTE PTR I_ECX[1]
2575 MOV AH, 3CH ; umask is applied by
2576 PUSH DS ; function 3CH
2577 MOV DS, SI
2578 INT 21H
2579 POP DS
2580 JC SHORT SYS2B_ERR
2581 MOV I_EAX, EAX ; Save the handle
2582 JMP SHORT SYS2B_SUCCESS ; Done
2583
2584SYS2B_ERR: MOV I_ECX, EAX
2585 MOV I_EAX, -1
2586 RET
2587
2588SYS2B_EXFAIL: MOV EBX, EAX ; File handle
2589 MOV AH, 3EH ; Close handle
2590 INT 21H
2591 MOV EAX, EEXIST
2592 JMP SHORT SYS2B_ERR
2593
2594; ----------------------------------------------------------------------------
2595; AX=7F2CH: __newthread
2596;
2597; Notify emx of new thread
2598;
2599; In: EDX Thread ID
2600;
2601; ----------------------------------------------------------------------------
2602
2603 TALIGN 4
2604SYS2C: MOV I_ECX, ENOSYS
2605 MOV I_EAX, -1
2606 RET
2607
2608; ----------------------------------------------------------------------------
2609; AX=7F2DH: __endthread
2610;
2611; Notify emx of end of thread
2612;
2613; In: EDX Thread ID
2614;
2615; ----------------------------------------------------------------------------
2616
2617 TALIGN 4
2618SYS2D: MOV I_ECX, ENOSYS
2619 MOV I_EAX, -1
2620 RET
2621
2622; ----------------------------------------------------------------------------
2623; AX=7F2EH: __waitpid()
2624;
2625; Wait for child process
2626;
2627; In: EDX Process ID
2628; ECX Options
2629;
2630; Out: EAX Process ID of child process (-1 if no children)
2631; ECX errno
2632; EDX Termination status
2633;
2634; ----------------------------------------------------------------------------
2635
2636 TALIGN 4
2637SYS2E: MOV I_ECX, ENOSYS
2638 MOV I_EDX, 0
2639 MOV I_EAX, -1
2640 RET
2641
2642; ----------------------------------------------------------------------------
2643; AX=7F2FH: __read_kbd()
2644;
2645; Keyboard input
2646;
2647; In: EDX flags (bit 0: echo, bit 1: wait, bit 2:sig)
2648;
2649; Out: EAX Character (or -1)
2650;
2651; ----------------------------------------------------------------------------
2652
2653RK_ECHO = 1
2654RK_WAIT = 2
2655RK_SIG = 4
2656
2657 TALIGN 4
2658SYS2F: TEST I_EDX, RK_SIG
2659 JNZ SHORT RKBD_SIG
2660 TEST I_EDX, RK_WAIT
2661 JNZ SHORT RKBD_WAIT
2662 MOV DL, 0FFH
2663 MOV AH, 06H
2664 INT 21H
2665 JZ SHORT RKBD_NOTHING
2666 MOVZX EAX, AL
2667RKBD_ECHO: TEST I_EDX, RK_ECHO
2668 JZ RKBD_RET
2669 PUSH EAX
2670 MOV DL, AL
2671 MOV AH, 06H
2672 INT 21H
2673 POP EAX
2674RKBD_RET: MOV I_EAX, EAX
2675 RET
2676
2677RKBD_WAIT: MOV AH, 07H
2678 INT 21H
2679 MOVZX EAX, AL
2680 JMP SHORT RKBD_ECHO
2681
2682RKBD_SIG: TEST I_EDX, RK_WAIT
2683 JNZ SHORT RKBD_SIG_WAIT
2684 MOV AH, 0BH
2685 INT 21H
2686 OR AL, AL
2687 JZ SHORT RKBD_NOTHING
2688RKBD_SIG_WAIT: TEST I_EDX, RK_ECHO
2689 JNZ SHORT RKBD_SIG_ECHO
2690 MOV AH, 08H
2691 INT 21H
2692 MOVZX EAX, AL
2693 JMP SHORT RKBD_RET
2694
2695RKBD_SIG_ECHO: MOV AH, 01H
2696 INT 21H
2697 MOVZX EAX, AL
2698 JMP SHORT RKBD_RET
2699
2700RKBD_NOTHING: MOV EAX, -1
2701 JMP SHORT RKBD_RET
2702
2703
2704; ----------------------------------------------------------------------------
2705; AX=7F30H: __sleep2()
2706;
2707; Suspend process
2708;
2709; In: EDX Milliseconds
2710;
2711; Out: EAX 0
2712;
2713; ----------------------------------------------------------------------------
2714
2715 TALIGN 4
2716SYS30: MOV I_EAX, 0 ; Return value
2717 MOV EAX, I_EDX
2718 OR EAX, EAX
2719 JZ SHORT SYS30_RET
2720 MOV ECX, 91
2721 MUL ECX ; Multiply by 0.0182 = 91/5000
2722 ADD EAX, 4999
2723 ADC EDX, 0
2724 MOV ECX, 5000
2725 DIV ECX
2726 MOV BX, DI
2727 CALL SLEEP ; Suspend process
2728SYS30_RET: RET
2729
2730
2731; ----------------------------------------------------------------------------
2732; AX=7F31H: __unwind2()
2733;
2734; Unwind signal handlers for longjmp()
2735;
2736; Currently not used by the DOS version of emx.
2737;
2738; ----------------------------------------------------------------------------
2739
2740 TALIGN 4
2741SYS31: RET
2742
2743
2744; ----------------------------------------------------------------------------
2745; AX=7F32H: __pause()
2746;
2747; Wait for signal
2748;
2749; Currently not implemented
2750;
2751; ----------------------------------------------------------------------------
2752
2753 TALIGN 4
2754SYS32: RET
2755
2756
2757; ----------------------------------------------------------------------------
2758; AX=7F33H: __execname()
2759;
2760; Get the name of the executable file
2761;
2762; In: EDX Buffer
2763; ECX Buffer size
2764;
2765; Out: EAX 0 if successful, -1 otherwise
2766;
2767; ----------------------------------------------------------------------------
2768 TALIGN 4
2769SYS33: MOV I_EAX, -1
2770 RET
2771
2772
2773; ----------------------------------------------------------------------------
2774; AX=7F34H: __initthread()
2775;
2776; Install exception handler in new thread
2777;
2778; In: EDX Pointer to EXCEPTIONREGISTRATIONRECORD
2779;
2780; Out: EAX 0 if successful, -1 otherwise
2781;
2782; ----------------------------------------------------------------------------
2783 TALIGN 4
2784SYS34: MOV I_EAX, -1
2785 RET
2786
2787
2788; ----------------------------------------------------------------------------
2789; AX=7F35H: __sigaction()
2790;
2791; Examine or specify action for a signal
2792;
2793; In: ECX Signal number
2794; EDX Pointer to sigaction structure (input)
2795; EBX Pointer to sigaction structure (output)
2796;
2797; Out: EAX 0 if successful, -1 otherwise
2798; ECX errno (0 if no error)
2799;
2800; ----------------------------------------------------------------------------
2801 TALIGN 4
2802 ASSUME DI:PTR PROCESS
2803SYS35: MOV EAX, I_ECX
2804 MOV EDX, I_EDX
2805 MOV EBX, I_EBX
2806 MOV ES, I_DS
2807 CALL DO_SIGACTION
2808 MOV I_ECX, EAX
2809 MOV I_EAX, 0
2810 TEST EAX, EAX
2811 JZ SHORT SYS35_RET
2812 MOV I_EAX, -1
2813SYS35_RET: RET
2814
2815
2816; ----------------------------------------------------------------------------
2817; AX=7F36H: __sigpending()
2818;
2819; Query set of pending signals
2820;
2821; In: EDX Pointer to sigset_t (output)
2822;
2823; Out: EAX 0 if successful, -1 otherwise
2824; ECX errno (0 if no error)
2825;
2826; ----------------------------------------------------------------------------
2827 TALIGN 4
2828 ASSUME DI:PTR PROCESS
2829SYS36: MOV EAX, [DI].P_SIG_BLOCKED
2830 AND EAX, [DI].P_SIG_PENDING
2831 SHR EAX, 1
2832 MOV EBX, I_EDX
2833 MOV ES, I_DS
2834 MOV ES:[EBX], EAX
2835 MOV I_EAX, 0
2836 MOV I_ECX, 0
2837 RET
2838
2839
2840; ----------------------------------------------------------------------------
2841; AX=7F37H: __sigprocmask()
2842;
2843; Examine or change the signal mask
2844;
2845; In: ECX Manner in which to set the mask
2846; EDX Pointer to sigset_t (input)
2847; EBX Pointer to sigset_t (output)
2848;
2849; Out: EAX 0 if successful, -1 otherwise
2850; ECX errno (0 if no error)
2851;
2852; ----------------------------------------------------------------------------
2853 TALIGN 4
2854 ASSUME DI:PTR PROCESS
2855SYS37: PUSH [DI].P_SIG_BLOCKED
2856 MOV EBX, I_EDX
2857 TEST EBX, EBX
2858 JZ SHORT SPM_NO_INPUT
2859 MOV ES, I_DS
2860 MOV EAX, ES:[EBX]
2861 SHL EAX, 1
2862 CMP I_ECX, SIG_BLOCK
2863 JE SHORT SPM_BLOCK
2864 CMP I_ECX, SIG_UNBLOCK
2865 JE SHORT SPM_UNBLOCK
2866 CMP I_ECX, SIG_SETMASK
2867 JE SHORT SPM_SETMASK
2868 POP EAX
2869 MOV I_EAX, -1
2870 MOV I_ECX, EINVAL
2871 RET
2872
2873SPM_UNBLOCK: NOT EAX
2874 AND EAX, [DI].P_SIG_BLOCKED
2875 JMP SHORT SPM_SETMASK
2876
2877SPM_BLOCK: OR EAX, [DI].P_SIG_BLOCKED
2878SPM_SETMASK: AND EAX, SIG_BLOCK_MASK
2879 MOV [DI].P_SIG_BLOCKED, EAX
2880SPM_NO_INPUT: POP EAX
2881 MOV EBX, I_EBX
2882 TEST EBX, EBX
2883 JZ SHORT SPM_NO_OUTPUT
2884 SHR EAX, 1
2885 MOV ES:[EBX], EAX
2886SPM_NO_OUTPUT: MOV I_EAX, 0
2887 MOV I_ECX, 0
2888 RET
2889
2890
2891; ----------------------------------------------------------------------------
2892; AX=7F38H: __sigsuspend()
2893;
2894; Replace signal mask and wait for signal
2895;
2896; In: EDX Pointer to sigset_t (input)
2897;
2898; Out: EAX 0 if successful, -1 otherwise
2899; ECX errno (0 if no error)
2900;
2901; Currently not implemented
2902;
2903; ----------------------------------------------------------------------------
2904 TALIGN 4
2905 ASSUME DI:PTR PROCESS
2906SYS38: MOV I_EAX, -1
2907 MOV I_ECX, ENOSYS
2908 RET
2909
2910; ----------------------------------------------------------------------------
2911; AX=7F39H: __imphandle()
2912;
2913; Import a file handle
2914;
2915; In: EDX File handle
2916;
2917; Out: EAX Relocated file handle (success) or -1 (failure)
2918; ECX errno (0 if no error)
2919;
2920; ----------------------------------------------------------------------------
2921
2922 TALIGN 4
2923SYS39: MOV I_ECX, ENOSYS
2924 MOV I_EAX, -1
2925 RET
2926
2927; ----------------------------------------------------------------------------
2928; AX=7F3AH: __fpuemu()
2929;
2930; Interface for floating point emulator
2931;
2932; In: ECX Command code
2933; EDX Pointer to communication area
2934;
2935; Out: EAX Relocated file handle (success) or -1 (failure)
2936; ECX errno (0 if no error)
2937;
2938; ----------------------------------------------------------------------------
2939 TALIGN 4
2940 ASSUME DI:PTR PROCESS
2941SYS3A: CMP I_ECX, FPUC_INIT
2942 JE SHORT FPUEMU_INIT
2943 CMP PROCESS_FPUEMU, DI ; Correct process?
2944 JNE FPUEMU_FAIL ; No -> fail
2945 CMP I_ECX, FPUC_NEXT
2946 JE SHORT FPUEMU_NEXT ; Yes -> wait for notification
2947 CMP I_ECX, FPUC_SIGNAL
2948 JE FPUEMU_SIGNAL
2949
2950;
2951; The FP emulator waits for the next notification; switch back to the
2952; interrupted process
2953;
2954FPUEMU_NEXT: CMP FPUEMU_STATE, FES_ON
2955 JNE SHORT FPUEMU_NEXT_1
2956 MOV AX, 0
2957 MOV FS, AX ; Avoid trap on POP FS
2958 MOV [DI].P_STATUS, PS_FPUEMU_NEXT
2959 MOV BX, DI
2960 CALL SAVE_PROCESS
2961 MOV DI, PROCESS_FPUCLIENT
2962 ASSUME DI:PTR PROCESS
2963 MOV PROCESS_PTR, DI
2964 MOV ES, I_DS
2965 MOV ESI, I_EDX
2966 ASSUME ESI:NEAR32 PTR FPUEMU_COM
2967 MOV CX, I_REG_DWORDS
2968 XOR EBX, EBX
2969FEN_LOOP: MOV EAX, ES:[ESI].FEC_FRAME[EBX]
2970 MOV DWORD PTR [DI].P_GS[BX], EAX
2971 ADD BX, 4
2972 LOOP FEN_LOOP
2973 MOV BX, DI
2974 CALL REST_PROCESS
2975;;;; CALL BREAK_AFTER_IRET
2976 ASSUME DI:NOTHING
2977 RET
2978
2979FPUEMU_INIT: CMP PROCESS_FPUEMU, NO_PROCESS ; FPU emu already installed?
2980 JNE FPUEMU_FAIL
2981 CMP FPUEMU_STATE, FES_LOADING
2982 JNE FPUEMU_FAIL
2983 MOV PROCESS_FPUEMU, DI
2984 MOV FPUEMU_STATE, FES_INIT1
2985 JMP EMX_OK
2986
2987 ASSUME DI:PTR PROCESS
2988FPUEMU_NEXT_1: CMP FPUEMU_STATE, FES_ENDPROC
2989 JE FPUEMU_ENDPROC_1
2990 CMP FPUEMU_STATE, FES_NEWPROC
2991 JE SHORT FPUEMU_NEWPROC_1
2992 CMP FPUEMU_STATE, FES_INIT1
2993 JNE FPUEMU_EXIT ; TODO
2994;
2995; Send FPUN_NEWPROC notifications for all processes
2996;
2997 LEA BX, PROCESS_TABLE
2998 ASSUME BX:PTR PROCESS
2999 MOV CX, MAX_PROCESSES
3000NEWPROC_LOOP: TEST [BX].P_FLAGS, PF_FPUEMU_INIT
3001 JNZ SHORT NEWPROC_NEXT
3002 CMP [BX].P_STATUS, PS_NONE
3003 JE SHORT NEWPROC_NEXT
3004 CMP [BX].P_STATUS, PS_DEFUNCT
3005 JE SHORT NEWPROC_NEXT
3006 CMP [BX].P_STATUS, PS_INIT
3007 JE SHORT NEWPROC_NEXT
3008 CMP BX, PROCESS_FPUEMU
3009 JNE SHORT NEWPROC_SEND
3010NEWPROC_NEXT: ADD BX, SIZE PROCESS
3011 LOOP NEWPROC_LOOP
3012 ASSUME BX:NOTHING
3013;
3014; All processes have been processed, send FPUN_EMU notification
3015;
3016FPUEMU_NEXT_INIT2:
3017 MOV FPUEMU_STATE, FES_ON
3018 MOV BX, PROCESS_PTR
3019 CALL SAVE_PROCESS
3020 MOV BX, PROCESS_FPUCLIENT
3021 MOV PROCESS_PTR, BX
3022 CALL REST_PROCESS
3023 CALL FPUEMU_CALL
3024 JMP EMX_OK
3025
3026;
3027; Send a FPUN_NEWPROC notification
3028;
3029 ASSUME BX:PTR PROCESS
3030NEWPROC_SEND: OR [BX].P_FLAGS, PF_FPUEMU_INIT
3031 MOV ES, I_DS
3032 MOV EDI, I_EDX
3033 ASSUME EDI:NEAR32 PTR FPUEMU_COM
3034 MOV ES:[EDI].FEC_NOTIFY, FPUN_NEWPROC
3035 MOV EAX, [BX].P_NUMBER
3036 MOV ES:[EDI].FEC_PNUM, EAX
3037 JMP EMX_OK
3038
3039 ASSUME EDI:NOTHING
3040 ASSUME BX:NOTHING
3041
3042;
3043; FPUN_ENDPROC and FPUN_NEWPROC handled
3044;
3045 ASSUME DI:PTR PROCESS
3046FPUEMU_ENDPROC_1:
3047FPUEMU_NEWPROC_1:
3048 MOV FPUEMU_STATE, FES_ON
3049 MOV [DI].P_STATUS, PS_FPUEMU_NEXT
3050 MOV BX, DI
3051 CALL SAVE_PROCESS
3052 MOV BX, PROCESS_FPUCLIENT
3053 MOV PROCESS_PTR, BX
3054 CALL REST_PROCESS
3055 RET
3056
3057;
3058; Generate a signal. Faking an exception would be better, but this
3059; will do for now.
3060;
3061FPUEMU_SIGNAL: MOV ES, I_DS
3062 MOV ESI, I_EDX
3063 ASSUME ESI:NEAR32 PTR FPUEMU_COM
3064 MOV EAX, ES:[ESI].FEC_SIGNAL
3065 MOV BX, PROCESS_FPUCLIENT
3066 BTS (PROCESS PTR [BX]).P_SIG_PENDING, EAX ; Generate signal
3067 JMP EMX_OK
3068 ASSUME ESI:NOTHING
3069
3070;
3071; TODO: Error message
3072;
3073FPUEMU_EXIT: MOV AX, 4CFFH
3074 INT 21H
3075
3076FPUEMU_FAIL: MOV I_ECX, EINVAL
3077 MOV I_EAX, -1
3078 RET
3079
3080 ASSUME DI:NOTHING
3081
3082; ----------------------------------------------------------------------------
3083; AX=7F58H: __settime()
3084;
3085; Set system time
3086;
3087; In: EDX Pointer to struct timeval
3088;
3089; Out: EAX 0 (success) or -1 (failure)
3090; ECX errno (0 if no error)
3091;
3092; ----------------------------------------------------------------------------
3093 TALIGN 4
3094SYS58: MOV ESI, I_EDX
3095 MOV ES, I_DS
3096 CALL DO_SETTIME
3097 MOV I_ECX, EAX
3098 MOV I_EAX, 0
3099 TEST EAX, EAX
3100 JZ SHORT SYS58_RET
3101 MOV I_EAX, -1
3102SYS58_RET: RET
3103
3104; ----------------------------------------------------------------------------
3105; AX=7F59H: __profil()
3106;
3107; Sampling profiler
3108;
3109; In: EDX Pointer to struct _profil
3110;
3111; Out: EAX 0 (success) or -1 (failure)
3112; ECX errno (0 if no error)
3113;
3114; ----------------------------------------------------------------------------
3115 TALIGN 4
3116 ASSUME DI:PTR PROCESS
3117SYS59: MOV ES, I_DS
3118 MOV ESI, I_EDX
3119 CALL DO_PROFIL
3120 MOV I_ECX, EAX
3121 TEST EAX, EAX
3122 JZ SHORT SYS59_1
3123 MOV EAX, -1
3124SYS59_1: MOV I_EAX, EAX
3125 RET
3126
3127; ----------------------------------------------------------------------------
3128; AX=7F5AH: __nls_ctype()
3129;
3130; Mark DBCS lead bytes
3131;
3132; In: EDX pointer to buffer
3133;
3134; Out: EAX 0 (success) or -1 (failure)
3135; ECX errno (0 if no error)
3136;
3137; ----------------------------------------------------------------------------
3138 TALIGN 4
3139SYS5A: CALL GET_DBCS_LEAD
3140 TEST AX, AX
3141 JZ SHORT NLS_CT_COPY
3142 JMP SYSCALL_ENOSYS
3143
3144;
3145; Copy the DBCS lead byte bits of our table to the target buffer
3146;
3147NLS_CT_COPY: CMP I_DS, 0 ; See INIT_DBCS
3148 JE SHORT NLS_CT_EFAULT
3149 MOV ES, I_DS
3150 MOV EDI, I_EDX
3151 MOV ECX, 0
3152 TALIGN 4
3153NLS_CT_COPY_BIT:BT DBCS_LEAD_TAB, CX
3154 JC SHORT NLS_CT_COPY_SET
3155 AND BYTE PTR ES:[EDI], 0FEH ; Clear _NLS_DBCS_LEAD
3156NLS_CT_COPY_NXT:INC EDI
3157 INC CX
3158 CMP CX, 256
3159 JB SHORT NLS_CT_COPY_BIT
3160 JMP EMX_OK
3161
3162 TALIGN 4
3163NLS_CT_COPY_SET:OR BYTE PTR ES:[EDI], 01H ; Set _NLS_DBCS_LEAD
3164 JMP SHORT NLS_CT_COPY_NXT
3165
3166NLS_CT_EFAULT: MOV I_EAX, -1
3167 MOV I_ECX, EFAULT
3168 RET
3169
3170 ASSUME BP:NOTHING
3171
3172; ----------------------------------------------------------------------------
3173;
3174; Convert a MY_DATETIME structure to Unix time format
3175;
3176; MDT must be in the stack!
3177;
3178; ----------------------------------------------------------------------------
3179 TALIGN 4
3180TIME_2_UNIX PROC PASCAL USES EBX ESI, MDT:PTR MY_DATETIME
3181 MOV BX, MDT
3182 ASSUME BX:PTR MY_DATETIME
3183 MOV EAX, SS:[BX].YEAR
3184 MOV EDX, 365
3185 MUL EDX
3186 MOV ESI, EAX
3187 MOV EAX, SS:[BX].MONTH
3188 DEC EAX
3189 MOV EDX, 31
3190 MUL EDX
3191 ADD ESI, EAX
3192 ADD ESI, SS:[BX].DAY ; 365*year + day + 31*(month-1)
3193 DEC SS:[BX].YEAR
3194 CMP SS:[BX].MONTH, 2 ; Jan or Feb?
3195 JBE SHORT T2U_1 ; Yes -> skip
3196
3197 INC SS:[BX].YEAR
3198 MOV EAX, SS:[BX].MONTH
3199 SHL EAX, 2
3200 ADD EAX, 23
3201 XOR EDX, EDX
3202 MOV ECX, 10
3203 DIV ECX
3204 SUB ESI, EAX ; - ((4*month)+23)/10
3205
3206 TALIGN 4
3207T2U_1: MOV EAX, SS:[BX].YEAR
3208 SHR EAX, 2
3209 ADD ESI, EAX ; + (year{-1})/4
3210 MOV EAX, SS:[BX].YEAR
3211 XOR EDX, EDX
3212 MOV ECX, 100
3213 DIV ECX
3214 INC EAX
3215 MOV EDX, EAX
3216 ADD EAX, EAX
3217 ADD EAX, EDX
3218 SHR EAX, 2
3219 SUB ESI, EAX ; - (3*((year{-1})/100+1)) / 4
3220 MOV EAX, ESI
3221 SUB EAX, 719528 ; 01-Jan-1970
3222 MOV EDX, 24*60*60
3223 MUL EDX
3224;
3225; Add time of day
3226;
3227 ADD EAX, SS:[BX].SECONDS
3228 MOV ESI, EAX
3229 MOV EAX, SS:[BX].MINUTES
3230 MOV EDX, 60
3231 MUL EDX
3232 ADD ESI, EAX
3233 MOV EAX, SS:[BX].HOURS
3234 MOV EDX, 60*60
3235 MUL EDX
3236 ADD EAX, ESI
3237 RET
3238 ASSUME BX:NOTHING
3239TIME_2_UNIX ENDP
3240
3241; ----------------------------------------------------------------------------
3242; Convert a packed time/date value to Unix time value (GMT)
3243;
3244; In: CX Time
3245; DX Date
3246;
3247; Out: EAX Unix time
3248;
3249; ----------------------------------------------------------------------------
3250;
3251 TALIGN 4
3252PACKED_2_UNIX PROC
3253 LOCAL MDT:MY_DATETIME
3254 MOV AX, DX ; Day of month
3255 AND EAX, 1FH
3256 MOV MDT.DAY, EAX
3257 MOV AX, DX ; Month
3258 SHR AX, 5
3259 AND EAX, 0FH
3260 MOV MDT.MONTH, EAX
3261 MOV AX, DX ; Year - 1980
3262 SHR AX, 9
3263 AND EAX, 7FH
3264 ADD EAX, 1980
3265 MOV MDT.YEAR, EAX
3266 MOV AX, CX ; Seconds / 2
3267 AND EAX, 1FH
3268 SHL EAX, 1
3269 MOV MDT.SECONDS, EAX
3270 MOV AX, CX ; Minutes
3271 SHR AX, 5
3272 AND EAX, 3FH
3273 MOV MDT.MINUTES, EAX
3274 MOV AX, CX ; Hours
3275 SHR AX, 11
3276 AND EAX, 1FH
3277 MOV MDT.HOURS, EAX
3278 INVOKE TIME_2_UNIX, ADDR MDT
3279 RET
3280PACKED_2_UNIX ENDP
3281
3282
3283;
3284; In: EAX Year
3285;
3286; Out: EAX 1 if leap year, 0 otherwise
3287;
3288 TALIGN 4
3289LEAP_YEAR PROC NEAR
3290 PUSH ECX
3291 PUSH EDX
3292 TEST EAX, 3 ; year = 4n?
3293 JNZ SHORT LEAP_NO ; No -> not a leap year
3294 MOV ECX, 100
3295 XOR EDX, EDX
3296 DIV ECX
3297 OR EDX, EDX ; year = 100n?
3298 JNZ SHORT LEAP_YES ; No -> it's a leap year
3299 TEST EAX, 3 ; year = 400n?
3300 JNZ SHORT LEAP_NO ; No -> not a leap year
3301LEAP_YES: XOR EAX, EAX
3302 INC EAX
3303 JMP SHORT LEAP_RET
3304
3305 TALIGN 4
3306LEAP_NO: XOR EAX, EAX
3307LEAP_RET: POP EDX
3308 POP ECX
3309 RET
3310LEAP_YEAR ENDP
3311
3312; ----------------------------------------------------------------------------
3313;
3314; Convert a Unix time value to a MY_DATETIME structure
3315;
3316; MDT must be in the stack!
3317;
3318; ----------------------------------------------------------------------------
3319 TALIGN 4
3320UNIX_2_TIME PROC PASCAL USES EBX ESI EDI,
3321 TIME:DWORD, MDT:PTR MY_DATETIME
3322 MOV BX, MDT
3323 ASSUME BX:PTR MY_DATETIME
3324 MOV EAX, TIME
3325 MOV ECX, 60
3326 XOR EDX, EDX
3327 DIV ECX
3328 MOV SS:[BX].SECONDS, EDX
3329 XOR EDX, EDX
3330 DIV ECX
3331 MOV SS:[BX].MINUTES, EDX
3332 MOV ECX, 24
3333 XOR EDX, EDX
3334 DIV ECX
3335 MOV SS:[BX].HOURS, EDX
3336 MOV ESI, 1970
3337 MOV EDI, EAX
3338 TALIGN 4
3339U2T_Y_LOOP: MOV EAX, ESI
3340 CALL LEAP_YEAR
3341 ADD EAX, 365
3342 MOV ECX, EAX
3343 INC ESI
3344 SUB EDI, ECX
3345 JNC SHORT U2T_Y_LOOP
3346 ADD EDI, ECX
3347 DEC ESI
3348 MOV SS:[BX].YEAR, ESI
3349 MOV ESI, 0
3350 TALIGN 4
3351U2T_M_LOOP: CMP ESI, 1 ; February?
3352 JE SHORT U2T_M_FEB
3353 MOVZX ECX, MONTH_LEN[ESI]
3354 JMP SHORT U2T_M_CONT
3355 TALIGN 4
3356U2T_M_FEB: MOV EAX, SS:[BX].YEAR
3357 CALL LEAP_YEAR
3358 ADD EAX, 28
3359 MOV ECX, EAX
3360 TALIGN 4
3361U2T_M_CONT: INC ESI
3362 SUB EDI, ECX
3363 JNC SHORT U2T_M_LOOP
3364 ADD EDI, ECX
3365 MOV SS:[BX].MONTH, ESI
3366 INC EDI
3367 MOV SS:[BX].DAY, EDI
3368 RET
3369UNIX_2_TIME ENDP
3370
3371
3372;
3373; Convert Unix time value (GMT) to a packed time/date value
3374;
3375; In: EAX Unix time
3376;
3377; Out: CX Time
3378; DX Date
3379;
3380UNIX_2_PACKED PROC
3381 LOCAL MDT:MY_DATETIME
3382 INVOKE UNIX_2_TIME, EAX, ADDR MDT
3383
3384 MOV ECX, MDT.SECONDS
3385 SHR ECX, 1
3386 MOV EAX, MDT.MINUTES
3387 SHL EAX, 5
3388 OR ECX, EAX
3389 MOV EAX, MDT.HOURS
3390 SHL EAX, 11
3391 OR ECX, EAX
3392
3393 MOV EDX, MDT.DAY
3394 MOV EAX, MDT.MONTH
3395 SHL EAX, 5
3396 OR EDX, EAX
3397 MOV EAX, MDT.YEAR
3398 SUB EAX, 1980
3399 SHL EAX, 9
3400 OR EDX, EAX
3401 RET
3402UNIX_2_PACKED ENDP
3403
3404
3405;
3406; In: ES:EDI destination
3407;
3408 TALIGN 4
3409 ASSUME EDI:NEAR32 PTR TIMEB
3410DO_FTIME PROC
3411 LOCAL DATE_CX:WORD, DATE_DX:WORD
3412 LOCAL TIME_CX:WORD, TIME_DX:WORD
3413 LOCAL MDT:MY_DATETIME
3414
3415RETRY: MOV AH, 2AH
3416 INT 21H
3417 MOV DATE_CX, CX
3418 MOV DATE_DX, DX
3419 MOV AH, 2CH
3420 INT 21H
3421 MOV TIME_CX, CX
3422 MOV TIME_DX, DX
3423 MOV AH, 2AH
3424 INT 21H
3425 CMP CX, DATE_CX
3426 JNE SHORT RETRY
3427 CMP DX, DATE_DX
3428 JNE SHORT RETRY
3429
3430 MOVZX EAX, BYTE PTR TIME_DX[1]
3431 MOV MDT.SECONDS, EAX
3432 MOVZX EAX, BYTE PTR TIME_CX[0]
3433 MOV MDT.MINUTES, EAX
3434 MOVZX EAX, BYTE PTR TIME_CX[1]
3435 MOV MDT.HOURS, EAX
3436 MOVZX EAX, BYTE PTR DATE_DX[0]
3437 MOV MDT.DAY, EAX
3438 MOVZX EAX, BYTE PTR DATE_DX[1]
3439 MOV MDT.MONTH, EAX
3440 MOVZX EAX, DATE_CX
3441 MOV MDT.YEAR, EAX
3442
3443 INVOKE TIME_2_UNIX, ADDR MDT
3444
3445 MOV ES:[EDI].DSTFLAG, 0
3446 MOV ES:[EDI].TIME, EAX
3447 MOVZX EAX, BYTE PTR TIME_DX[0]
3448 MOV ECX, 10
3449 MUL ECX
3450 MOV ES:[EDI].MILLITM, EAX
3451 MOV ES:[EDI].TIMEZONE, 0
3452 ASSUME EDI:NOTHING
3453 RET
3454DO_FTIME ENDP
3455
3456
3457;
3458; In: ES:ESI Source
3459;
3460 TALIGN 4
3461 ASSUME ESI:NEAR32 PTR TIMEVAL
3462DO_SETTIME PROC
3463 LOCAL MDT:MY_DATETIME
3464 MOV EAX, ES:[ESI].TV_USEC
3465 XOR EDX, EDX
3466 MOV ECX, 1000000
3467 DIV ECX
3468 PUSH EDX ; Save microseconds
3469 ADD EAX, ES:[ESI].TV_SEC
3470 INVOKE UNIX_2_TIME, EAX, ADDR MDT
3471 POP EAX ; Microseconds
3472 XOR EDX, EDX
3473 MOV ECX, 10000
3474 DIV ECX ; 1/100 seconds
3475 MOV DL, CL
3476 MOV DH, BYTE PTR MDT.SECONDS
3477 MOV CL, BYTE PTR MDT.MINUTES
3478 MOV CH, BYTE PTR MDT.HOURS
3479 MOV AH, 2DH ; Set system time
3480 INT 21H
3481 TEST AL, AL
3482 JNZ SHORT ERROR
3483; TODO: Time window
3484 MOV DL, BYTE PTR MDT.DAY
3485 MOV DH, BYTE PTR MDT.MONTH
3486 MOV CX, WORD PTR MDT.YEAR
3487 MOV AH, 2BH ; Set system date
3488 INT 21H
3489 TEST AL, AL
3490 JNZ SHORT ERROR
3491 XOR EAX, EAX
3492 RET
3493
3494ERROR: MOV EAX, EINVAL
3495 RET
3496DO_SETTIME ENDP
3497
3498 ASSUME ESI:NOTHING
3499
3500
3501;
3502; Compare two strings
3503;
3504; In: DS:ESI First string
3505; ES:EDI Second string
3506;
3507; Out: ZR Strings are equal
3508; ESI Modified
3509; EDI Modified
3510;
3511 TALIGN 4
3512STRCMP PROC NEAR
3513SC_1: LODS BYTE PTR DS:[ESI]
3514 SCAS BYTE PTR ES:[EDI]
3515 JNE SHORT SC_RET
3516 OR AL, AL
3517 JNZ SHORT SC_1
3518SC_RET: RET
3519STRCMP ENDP
3520
3521;
3522; Compare two strings, disregarding letter case
3523;
3524; In: DS:SI First string
3525; ES:DI Second string
3526;
3527; Out: ZR Strings are equal
3528; SI Modified
3529;
3530 TALIGN 4
3531STRICMP PROC NEAR
3532 PUSH DI
3533SIC_1: LODSB
3534 CALL UPPER
3535 MOV AH, AL
3536 MOV AL, ES:[DI]
3537 INC DI
3538 CALL UPPER
3539 CMP AL, AH
3540 JNE SHORT SIC_RET
3541 OR AL, AL
3542 JNZ SHORT SIC_1
3543SIC_RET: POP DI
3544 RET
3545STRICMP ENDP
3546
3547
3548
3549SV_CODE ENDS
3550
3551 END
Note: See TracBrowser for help on using the repository browser.