diff --git a/plat/msdos86/include/sys/types.h b/plat/msdos86/include/sys/types.h index 6a0c3d3db..005f48eb0 100644 --- a/plat/msdos86/include/sys/types.h +++ b/plat/msdos86/include/sys/types.h @@ -1,7 +1,7 @@ #ifndef _SYS_TYPES_H #define _SYS_TYPES_H -typedef int pid_t; +typedef long pid_t; typedef int mode_t; typedef long time_t; typedef long suseconds_t; diff --git a/plat/msdos86/libsys/getpid.s b/plat/msdos86/libsys/getpid.s new file mode 100644 index 000000000..009c4f9f4 --- /dev/null +++ b/plat/msdos86/libsys/getpid.s @@ -0,0 +1,27 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Get the current process identifier. For MS-DOS, use the Program Segment +! Prefix (PSP) segment as the PID. +! +! (Note that pid_t is a 32-bit type. This is to allow for PSP addresses +! above 0x7FFF:0.) + +.define _getpid +_getpid: + movb ah, 0x51 + int 0x21 + xchg bx, ax + xor dx, dx + ret diff --git a/plat/msdos86/libsys/libsys.h b/plat/msdos86/libsys/libsys.h index ddba5cda6..3488c332e 100644 --- a/plat/msdos86/libsys/libsys.h +++ b/plat/msdos86/libsys/libsys.h @@ -49,5 +49,10 @@ extern ssize_t _sys_rawread(int, char *, size_t); extern ssize_t _sys_rawwrite(int, const char *, size_t); extern int _sys_isopen(int); extern int _sys_isreadyr(int); +extern int _sys_exists(const char *); +extern int _sys_rawcreat(const char *, unsigned); +extern int _sys_rawopen(const char *, int); +extern off_t _sys_rawlseek(int, off_t, int); + #endif diff --git a/plat/msdos86/libsys/lseek.c b/plat/msdos86/libsys/lseek.c new file mode 100644 index 000000000..db996a1dd --- /dev/null +++ b/plat/msdos86/libsys/lseek.c @@ -0,0 +1,26 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +#include +#include +#include +#include "libsys.h" + +off_t lseek(int fd, off_t offset, int whence) +{ + off_t newoff; + + if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) + { + errno = EINVAL; + return -1L; + } + + newoff = _sys_rawlseek(fd, offset, whence); + if (newoff != -1L) + _sys_seteof(fd, 0); + + return newoff; +} diff --git a/plat/msdos86/libsys/open.c b/plat/msdos86/libsys/open.c new file mode 100644 index 000000000..038ab004b --- /dev/null +++ b/plat/msdos86/libsys/open.c @@ -0,0 +1,101 @@ +/* $Source$ + * $State$ + * $Revision$ + */ + +/* + * Derived from dos-open.c for newlib-ia16 which was written for the + * gcc-ia16 toolchain. + * + * Copyright (c) 2018 Bart Oldeman + * Copyright (c) 2019--2021 TK Chia + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + +#include +#include +#include +#include +#include "libsys.h" + +int open(const char* pathname, int flags, ...) +{ + int fd = -1, binmode; + off_t ret; + + if ((flags & ~(O_ACCMODE | O_CREAT | O_TRUNC | O_APPEND + | O_TEXT | O_BINARY))) + { + /* bail out if there are unknown flags */ + errno = EINVAL; + return -1; + } + + binmode = flags & (O_TEXT | O_BINARY); + if (binmode != O_TEXT && binmode != O_BINARY && binmode != 0) + { + /* bail out if both O_TEXT and O_BINARY are specified (!) */ + errno = EINVAL; + return -1; + } + + if ((flags & O_CREAT)) + { + /* special but common case O_WRONLY | O_CREAT | O_TRUNC + * should be handled by only calling _sys_rawcreat */ + int fileexists = 0; + if (!(flags & O_TRUNC)) + fileexists = _sys_exists(pathname); + if (!fileexists) + { + va_list ap; + mode_t mode; + + va_start(ap, flags); + mode = va_arg(ap, mode_t); + va_end(ap); + + fd = _sys_rawcreat(pathname, mode & 0200 ? 0 : 1); + if (fd != -1) + { + if ((flags & O_ACCMODE) == O_WRONLY) + return fd; + close(fd); + fd = -1; + } + } + } + + /* try to open file with mode */ + if (fd == -1) + fd = _sys_rawopen(pathname, flags & O_ACCMODE); + if (fd == -1) + return fd; + ret = 0; + + /* handle O_TRUNC and O_APPEND */ + if ((flags & O_TRUNC)) + ret = _sys_rawwrite(fd, NULL, 0); + else if ((flags & O_APPEND)) + ret = _sys_rawlseek(fd, 0L, SEEK_END); + if (ret == -1) + { + close(fd); + return -1; + } + + /* handle O_TEXT and O_BINARY, and reset "end of file encountered" */ + _sys_setmode(fd, binmode == O_BINARY ? O_BINARY : O_TEXT); + _sys_seteof(fd, 0); + + return fd; +} diff --git a/plat/msdos86/libsys/sys_exists.s b/plat/msdos86/libsys/sys_exists.s new file mode 100644 index 000000000..e282ef687 --- /dev/null +++ b/plat/msdos86/libsys/sys_exists.s @@ -0,0 +1,25 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Say whether a file exists with the given name. + +.define __sys_exists +__sys_exists: + mov bx, sp + mov dx, 2(bx) + mov ax, 0x4300 + int 0x21 + sbb ax, ax + inc ax + ret diff --git a/plat/msdos86/libsys/sys_rawcreat.s b/plat/msdos86/libsys/sys_rawcreat.s new file mode 100644 index 000000000..67bc34e59 --- /dev/null +++ b/plat/msdos86/libsys/sys_rawcreat.s @@ -0,0 +1,24 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Create or truncate a file. + +.define __sys_rawcreat +__sys_rawcreat: + movb ah, 0x3c + mov bx, sp + mov dx, 2(bx) + mov cx, 4(bx) + int 0x21 + jmp .sys_axret diff --git a/plat/msdos86/libsys/sys_rawlseek.s b/plat/msdos86/libsys/sys_rawlseek.s new file mode 100644 index 000000000..992c4c655 --- /dev/null +++ b/plat/msdos86/libsys/sys_rawlseek.s @@ -0,0 +1,26 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Move the current file position for a file descriptor. + +.define __sys_rawlseek +__sys_rawlseek: + movb ah, 0x42 + mov bx, sp + mov dx, 4(bx) + mov cx, 6(bx) + movb al, 8(bx) + mov bx, 2(bx) + int 0x21 + jmp .sys_dxaxret diff --git a/plat/msdos86/libsys/sys_rawopen.s b/plat/msdos86/libsys/sys_rawopen.s new file mode 100644 index 000000000..301e2fded --- /dev/null +++ b/plat/msdos86/libsys/sys_rawopen.s @@ -0,0 +1,24 @@ +# +! $Source$ +! $State$ +! $Revision$ + +! Declare segments (the order is important). + +.sect .text +.sect .rom +.sect .data +.sect .bss + +.sect .text + +! Open an existing file. + +.define __sys_rawopen +__sys_rawopen: + movb ah, 0x3d + mov bx, sp + mov dx, 2(bx) + movb al, 4(bx) + int 0x21 + jmp .sys_axret diff --git a/plat/msdos86/libsys/sys_seterrno.c b/plat/msdos86/libsys/sys_seterrno.c index 779e600f5..b135aea33 100644 --- a/plat/msdos86/libsys/sys_seterrno.c +++ b/plat/msdos86/libsys/sys_seterrno.c @@ -33,9 +33,9 @@ static const signed char err_map[] = /* * Map an MS-DOS 2+ system error code to an `errno' value and store that in - * `errno'. Return -1. + * `errno'. Return a longword -1. */ -int _sys_seterrno(unsigned dos_err) +long _sys_seterrno(unsigned dos_err) { if (dos_err < sizeof(err_map) / sizeof(err_map[0])) errno = err_map[dos_err]; diff --git a/plat/msdos86/libsys/sys_xret.s b/plat/msdos86/libsys/sys_xret.s index a5b65116a..57f407ef4 100644 --- a/plat/msdos86/libsys/sys_xret.s +++ b/plat/msdos86/libsys/sys_xret.s @@ -13,20 +13,26 @@ .sect .text ! .sys_zret: if the carry flag is set, then set `errno' from the DOS error -! code in ax, and return -1. If the carry flag is clear, just return zero. +! code in ax, and return a shortword -1. If the carry flag is clear, just +! return a shortword zero. ! ! .sys_axret: if the carry flag is set, then set `errno' from the DOS error -! code in ax, and return -1. If the carry flag is clear, just return ax as -! a return value. +! code in ax, and return a shortword -1. If the carry flag is clear, just +! return ax as a return value. +! +! .sys_dxaxret: same as .sys_axret, but return a longword -1 or dx:ax as a +! return value. .extern .sys_zret .extern .sys_axret +.extern .sys_dxaxret .sys_zret: jc error xor ax, ax no_error: ret .sys_axret: +.sys_dxaxret: jnc no_error error: push ax