/* Copyright (C) 1995,1996 Robert de Bath * This file is part of the Linux-8086 C library and is distributed * under the GNU Library General Public License. */ #if !__FIRST_ARG_IN_AX__ #ifdef __AS386_16__ #ifdef __MSDOS__ #include #include #include int errno; unsigned _doserrno; #ifdef L_dos_start static char * defarg[2] = { "C" }; static char ** def_environ =defarg+1; void (*__cleanup)() = 0; #asm .data export ___envseg ___envseg: .word 0 export ___psp ___psp: .word 0 .text export _exit export __exit _exit: ! exit(rv) function mov bx,sp push [bx+2] ! Copy the `rv` for the exit fuctions. mov bx,[___cleanup] ! Call exit, normally this is `__do_exit` test bx,bx je no_clean ! But it`s default is null call bx no_clean: inc sp inc sp __exit: ! _exit(rv) mov bx,sp mov ax,[bx+2] mov ah,#$4c int #$21 dos_1_exit: int #$20 .text export ___cstartup ! Crt0 startup ___cstartup: mov ax,#$3000 ! Get DOS version int $21 cmp al,#2 ! DOS 2+ is Ok jb dos_1_exit mov dx,cs ! Current CS add dx,#__segoff ! This var generated by the linker mov ds,dx ! Correct DS mov [___psp],es ! PSP segment seg es mov ax,[$2c] mov [___envseg],ax ! Enviroment Segment ! Now need to free some RAM seg es mov bx,[2] ! Top of Ram mov ax,ds add ax,#4096 ! Top of 64k data seg jc use_tor ! Oops, wrapped cmp ax,bx jnc use_tor ! Bigger than tor mov bx,ax use_tor: mov ax,cs ! Work out how big the memseg is needed sub bx,ax mov ah,#$4A ! Set it int $21 jnc set_stack ! Good. ! Ooops, problem.. ! BX is now how big it can be so set that. ! FIXME should check for BSS v Stack overlap mov ah,#$4A int $21 set_stack: ! Now set SS to the same as DS sub bx,#__segoff ! And SP to the top of available memory. mov cl,#4 shl bx,cl sub bx,#2 mov ss,dx mov sp,bx zap_bss: ! Clear the BSS mov es,dx ! ES now data seg mov di,#__edata mov cx,#__end sub cx,di xor ax,ax cld rep stosb push [_def_environ] ! Defaults for when nothing is used. mov ax,#_defarg push ax mov ax,#1 push ax mov si,#auto_start ! Pointer to first autostart function auto_run: mov bx,[si] test bx,bx jz no_entry call bx ! Call the function no_entry: inc si ! SI at next inc si jmp auto_run ! And round for the next. call_exit: ! Last item called by above. pop bx ! Be tidy. push ax ! At the end the last called was main() push it`s call _exit ! return val and call exit(); bad_exit: jmp bad_exit ! Exit returned !! loc 2 .word _main ! Segment 2 is the trailing pointers, main and the .word call_exit ! routine to call exit. data_start: .text #endasm __E_nosys() { #asm .text export sys_call5 export sys_call4 export sys_call3 export sys_call2 export sys_call1 export sys_call0 sys_call5: ! Trap the unemulated Linux86 syscalls sys_call4: sys_call3: sys_call2: sys_call1: sys_call0: #endasm errno = ENOSYS; return -1; } #endif #ifdef L___mkargv #ifdef __AS386_16__ #asm loc 1 ! Make sure the pointer is in the correct segment auto_func: ! Label for bcc -M to work. .word ___mkargv ! Pointer to the autorun function .text ! So the function after is also in the correct seg. #endasm #endif void set_program_name(__argv) char ** __argv; { unsigned char *ptr; int src,len; __set_es(__envseg); src=0; while(__peek_es(src++)!=0) { while(__peek_es(src++)!=0); } src+=2; // step over 0x0001 len=0; while (__peek_es(src+len++)!=0); ptr=sbrk(len); __argv[0]=ptr; while(len--) { *ptr++=__peek_es(src++); } } __mkargv(__argc, __argv) int __argc; char ** __argv; { int length, i, argc=1, s=0; unsigned char *ptr, *p; int es=__get_es(); set_program_name(__argv); __set_es(__psp); /* Pointer to the args */ length = __peek_es(0x80); /* Length of cmd line */ if( length > 0 ) { ptr = (char*) sbrk(length+1); /* Allocate some space */ for(i=0; i ' ' && s == 0 ) { argc++; s=1; } if( ptr[i] <= ' ' && s == 1 ) s=0; } ptr[length]=0; p= __argv[0]; __argv = (char**) sbrk((argc+1)*sizeof(char*)); __argv[0] = p; /* TODO: The real command can be found */ __argc=argc; /* * TODO: This needs to understand quoting and wildcards */ argc=1; s=0; for(i=0; i ' ' && s == 0 ) { __argv[argc++] = ptr+i; s=1; } if( ptr[i] <= ' ' && s == 1 ) { ptr[i] = '\0'; s=0; } } __argv[argc] = 0; } __set_es(es); } #endif #ifdef L___mkenvp #ifdef __AS386_16__ #asm loc 1 ! Make sure the pointer is in the correct segment auto_func: ! Label for bcc -M to work. .word ___mkenvp ! Pointer to the autorun function .text ! So the function after is also in the correct seg. #endasm #endif char ** environ = 0; __mkenvp(__argc, __argv, __envp) int __argc; char ** __argv; char ** __envp; { /* FIXME !!! * * Note must write to __envp argument but not touch __argv or __argc */ } #endif #ifdef L_dos__fconv /* This function converts filenames from unix like to DOS. */ char * __fconv(fname) char * fname; { static char buf1[66], buf2[66], *str = 0; register char *p, ch; int dot = 0; if( strcmp("/dev/tty", fname) == 0 ) return "CON:"; if( str == buf1 ) str = buf2; else str = buf1; p = str; if( strncmp("/mnt/", fname, 5) == 0 ) { strcpy(p, "A:"); p+=2; fname+=4; } /* * POSS: * open("/name/*", ...); looks for an environ var PATH_name=c:\x\y\z */ while((ch = *fname++) && p < str+65) { if( ( ch >= 'a' && ch <= 'z' ) || ( ch >= '0' && ch <= '9' ) || ch == ':' || ch == '%' || ch == '-' || ch == '$' ) ; else if( ch >= 'A' && ch <= 'Z' ) ch = ch-'A'+'a'; else if( ch == '.' && dot == 0 ) dot = 1; else if( ch == '/' || ch == '\\' ) { dot = 0; ch = '\\'; } else ch = '_'; *p++ = ch; } *p++ = '\0'; return str; } #endif #ifdef L___exterror static char errno_xlate[] = { 0, EINVAL, ENOENT, ENOENT, EMFILE, EACCES, EBADF, EFAULT, ENOMEM, EFAULT, ENOMEM, EINVAL, EINVAL, EINVAL, EINVAL, ENODEV, EPERM, EXDEV, ENFILE, EROFS, ENODEV, ENXIO, EINVAL, EIO, EINVAL, ESPIPE, EIO, EIO, EAGAIN, EIO, EIO, EIO, EBUSY, EBUSY, ENODEV, EFAULT, ENOLCK, EFAULT, EFAULT, ENOSPC }; __exterror() { #asm export exterror exterror: push ds push es push di push si push bp xor bx,bx mov ah,#$59 int $21 pop bp pop si pop di pop es pop ds mov __doserrno,ax #endasm { int nerrno; extern unsigned _doserrno; if( _doserrno == 0 ) /* No error? No change. */; else if( _doserrno >= sizeof(errno_xlate) || errno_xlate[_doserrno] == EFAULT ) errno = 16384+_doserrno; else errno = errno_xlate[_doserrno]; } return -1; } #endif #ifdef L_dos_read int read(fd, ptr, len) int fd; char *ptr; unsigned len; { #asm mov bx,sp mov cx,[bx+6] mov dx,[bx+4] mov bx,[bx+2] mov ah,#$3f int #$21 jnc readok br exterror readok: #endasm } #endif #ifdef L_dos_write int write(fd, ptr, len) int fd; char *ptr; unsigned len; { #asm mov bx,sp mov cx,[bx+6] mov dx,[bx+4] mov bx,[bx+2] mov ah,#$40 int #$21 jnc writeok br exterror writeok: #endasm } #endif #ifdef L_dos_open int open(fname, type, cmode) char * fname; int type; int cmode; { register char * nname = __fconv(fname); int creat_mode = 0; int rv; static int xlate_mode[] = { #ifdef OPEN_LIKE_UNIX O_RDONLY|O_DENYNONE, O_WRONLY|O_DENYNONE, O_RDWR|O_DENYNONE, #else O_RDONLY|O_DENYNONE, O_WRONLY|O_DENYWRITE, O_RDWR|O_DENYALL, #endif 3 }; if( (cmode & 0222) == 0 ) creat_mode = 1; /* BzzzT. Ignore O_EXCL */ if( type & O_TRUNC ) /* Assume TRUNC always means CREAT too */ rv = __dos_creat(nname, creat_mode); else { int sv = errno; /* If we would open in compatibility mode make it a little more unixy */ if( type & O_DENYMODE ) rv = __dos_open(nname, type&(O_ACCMODE|O_DENYMODE|O_SETFD)); else rv = __dos_open(nname, xlate_mode[type&O_ACCMODE]); if (rv == -1 && errno == ENOENT && (type & O_CREAT)) { errno = sv; rv = __dos_creat(nname, creat_mode); } } return rv; } __dos_open(fname, mode) { #asm mov bx,sp mov dx,[bx+2] ;ds:dx points to source string mov al,[bx+4] ;access code mov ah,#$3d ;ask for a open int #$21 jnc openok ;return handle if no error br exterror openok: #endasm } __dos_creat(fname) char * fname; { #asm mov bx,sp mov dx,[bx+2] ;ds:dx points to source string xor cx,cx ;normal attributes mov ah,#$3c ;ask for a create int #$21 jnc creok ;return handle if no error br exterror creok: #endasm } #endif #ifdef L_dos_close close(fd) { #asm mov bx,sp mov bx,[bx+2] ;file handle mov ah,#$3e ;ask for a close int #$21 mov ax,0 ;return 0 if no error jnc closeok br exterror closeok: #endasm } #endif #ifdef L_dos_unlink unlink(fname) char * fname; { #asm mov bx,sp push [bx+2] call ___fconv inc sp inc sp mov dx,ax ;ds:dx points to source string mov ah,#$41 ;ask for a unlink int #$21 mov ax,0 ;assume no errors jnc unlok br exterror unlok: #endasm } #endif #ifdef L_dos_lseek long lseek(fd, offset, mode) int fd, mode; long offset; { #asm mov bx,sp mov al,[bx+8] ;mode of seek (0 to 2) mov dx,[bx+4] ;cx:dx is long offset mov cx,[bx+6] mov bx,[bx+2] ;file handle mov ah,#$42 int #$21 ;do the lseek jnc seekok call exterror mov dx,ax seekok: #endasm } #endif #ifdef L_dos_segalloc unsigned int __segalloc(paracount) unsigned int paracount; { #asm mov bx,sp mov bx,[bx+2] mov ah,#$48 int $21 jnc ok mov ax,#0 ok: #endasm } #endif #ifdef L_dos_segfree unsigned int __segfree(segno) unsigned int segno; { #asm push es mov bx,sp mov es,[bx+4] mov ah,#$49 int $21 jc err mov ax,#0 err: pop es #endasm } #endif #ifdef L_dos_setvect void __setvect(i,j) int i; long j; { #asm mov bx,sp mov ax,[bx+2] mov dx,[bx+4] mov bx,[bx+6] push ds test bx,bx jnz got_seg mov bx,cs got_seg: mov ds,bx mov ah,#$25 int $21 pop ds #endasm } #endif #ifdef L_dos_getvect long __getvect(vecno) int vecno; { #asm mov bx,sp mov ax,[bx+2] mov ah,#$35 push es int #$21 mov dx,es mov ax,bx pop es #endasm } #endif #ifdef L_dos_getmod int __dos_getmod(fname) { #asm #if __FIRST_ARG_IN_AX__ mov dx,ax #else mov bx,sp mov dx,[bx+2] #endif mov ax,#$4300 int #$21 jnc statok br exterror statok: mov ax,cx #endasm } #endif #ifdef L_dos_stat int __dos_stat(fname, dtaptr) { #asm mov bx,sp #if __FIRST_ARG_IN_AX__ mov cx,ax mov dx,[bx+2] #else mov dx,[bx+4] #endif mov ah,#$1A ; Set DTA to requested int #$21 #if __FIRST_ARG_IN_AX__ mov ax,cx #else mov dx,[bx+2] #endif mov ax,#$4300 ; Locate the file int #$21 jc nonesuch mov ax,#$4e00 ; Get all the available information. int #$21 jc nonesuch xor ax,ax ret nonesuch: mov ax,#2 mov _errno,ax mov ax,#-1 #endasm } #endif #ifdef L_dos_isatty isatty(fd) int fd; { #asm mov bx,sp mov bx,[bx+2] mov ah,#$44 mov al,#0 int #$21 xor ax,ax test dx,#$80 jz not_tty inc ax not_tty: #endasm } #endif #ifdef L_dos_abort abort() { write(2, "Abnormal program termination\r\n", 30); _exit(3); } #endif #ifdef L_bdos bdos(dosfn, dosdx, dosal) int dosfn; unsigned dosdx, dosal; { #asm _bdosptr = _bdos mov bx,sp push si push di mov dx,_bdos.dosdx[bx] mov cx,_bdos.dosfn[bx] mov ax,_bdos.dosal[bx] mov ah,cl int $21 pop di pop si #endasm } #endif #endif /* __MSDOS__ */ #endif /* __AS386_16__ */ #endif /* !__FIRST_ARG_IN_AX__ */ /* # Name No Args Flag, comment CHDIR 12 1 TIME 13 1 * No long return val, arg _must_ exist. MKNOD 14 3 CHMOD 15 2 CHOWN 16 3 BRK 17 1 * This is only to tell the system STAT 18 2 GETPID 20 1 * This gets both pid & ppid MOUNT 21 3 * Need more args & no ELKS UMOUNT 22 1 . No ELKS SETUID 23 1 GETUID 24 1 * This gets both uid and euid STIME 25 2 . No ELKS should be 1 LONG arg PTRACE 26 X + ALARM 27 2 ? No unused return. FSTAT 28 2 PAUSE 29 0 UTIME 30 2 STTY 31 2 . ELKS ain't got this and it'll probably change GTTY 32 2 . ELKS ain't got this and it'll probably change ACCESS 33 2 NICE 34 1 FTIME 35 1 . ELKS ain't got this. SYNC 36 0 KILL 37 2 RENAME 38 2 MKDIR 39 2 RMDIR 40 1 DUP 41 X - Using nasty fcntl function PIPE 42 1 TIMES 43 1 PROF 44 X + SETGID 46 1 GETGID 47 1 * This gets both gid and egid SIGNAL 48 2 + ACCT 51 X + PLOCK 53 X + IOCTL 54 3 FCNTL 55 3 EXEC 59 2 ? UMASK 60 1 CHROOT 61 1 SIGACTION 71 X SIGSUSPEND 72 X SIGPENDING 73 X SIGPROCMASK 74 X SIGRETURN 75 X REBOOT 76 3 . No ELKS and the magic number will be diff. */