summaryrefslogtreecommitdiff
path: root/libc/msdos/msdos.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/msdos/msdos.c')
-rw-r--r--libc/msdos/msdos.c540
1 files changed, 540 insertions, 0 deletions
diff --git a/libc/msdos/msdos.c b/libc/msdos/msdos.c
new file mode 100644
index 0000000..02c35db
--- /dev/null
+++ b/libc/msdos/msdos.c
@@ -0,0 +1,540 @@
+/* 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;
+
+#ifdef L_dos_start
+
+static char * argdef[2] = { "C" };
+char ** __argv =argdef;
+char ** environ =argdef+1;
+
+int __argc =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
+
+ call ___mkargv ! Fetch the arguments and enviroment
+ push [_environ]
+ push [___argv]
+ push [___argc]
+
+ mov si,#auto_start ! Pointer to first autostart function
+auto_run:
+ call [si] ! Call the function
+ 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
+
+extern char ** environ;
+extern char ** __argv;
+extern int __argc;
+
+__mkargv()
+{
+ int length, i, argc=1, s=0;
+ 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; /* FIXME: The real command can be found */
+ __argc=argc;
+
+ 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_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_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
+ mov ax,#-1
+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
+ mov ax,#-1
+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;
+
+ 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
+ /* Warn, this assumes the standard vals for O_RDWR, O_RDONLY, O_WRONLY */
+ rv = __dos_open(nname, type&O_ACCMODE);
+ if( rv < 0 ) errno=ENOENT;
+ 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
+ mov ax,#-1 ;return -1 if error
+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
+ mov ax,#-1 ;return -1 if error
+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
+ mov ax,#-1 ;return -1 if error
+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
+ mov ax,#-1 ;return -1 if error
+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
+ mov ax,#-1 ;return -1 if error
+ 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_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_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
+
+#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.
+*/
+