Logo Search packages:      
Sourcecode: linux86 version File versions  Download package

msdos.c

/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
 * 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 <dos.h>
#include <fcntl.h>
#include <errno.h>
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

__mkargv(__argc, __argv)
int __argc;
char ** __argv;
{
   int length, i, argc=1, s=0;
   unsigned char *ptr, *p;
   __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<length; i++)       /* Copy it in. */
      {
      ptr[i] = __peek_es(0x81+i);
      if( ptr[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<length; i++)
      {
      if( ptr[i] >  ' ' && s == 0 ) { __argv[argc++] = ptr+i; s=1; }
      if( ptr[i] <= ' ' && s == 1 ) { ptr[i] = '\0'; s=0; }
      }
      __argv[argc] = 0;
   }
}
#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. Assume these flags both mean the merge of them */
   /* BzzzT. Also ignore O_EXCL */
   if( type & (O_TRUNC|O_CREAT) )
      rv = __dos_creat(nname, creat_mode);

   else
   {
      /* 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]);
   }
   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.
*/


Generated by  Doxygen 1.6.0   Back to index