📄 sysemx.c
字号:
/*****************************************************************************
* FILE: sysemx.c *
* *
* DESC: *
* - int 0x21 32 bit handler *
* - int 0x21 emx syscall handler *
* *
* Copyright (C) 1993,1994 *
* Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld *
* email: rainer@mathematik.uni-bielefeld.de *
* *
*****************************************************************************/
#include <string.h>
#include <malloc.h>
#include "DPMI.H"
#include "PRINTF.H"
#include "RMLIB.H"
#include "TIMEDOS.H"
#include "PROCESS.H"
#include "SIGNALS.H"
#include "GNUAOUT.H"
#include "START32.H"
#include "CDOSX32.H"
#include "COPY32.H"
#include "EXCEP32.H"
#include "RSX.H"
#include "STATEMX.H"
#include "PTRACE.H"
#include "LOADPRG.H"
#include "TERMIO.H"
#include "DOSERRNO.H"
#define CONVERT1_BX_HANDLE \
int h = get_dos_handle(BX); \
if (h < 0) { \
EAX = EMX_EBADF; \
return CARRY_ON; \
} \
else BX = h;
#define CONVERT2_BX_HANDLE \
int h = get_dos_handle(BX); \
if (h < 0) { \
set_ecx_error(EMX_EBADF); \
return CARRY_ON; \
} \
else BX = h;
static DWORD can_run_emx = 0x302e3961; /* ascii = 0.9a */
static int time_reached(unsigned long time)
{
if (time <= time_tic)
return 1;
else
return 0;
}
static void set_ecx_error(int err)
{
EAX = -1L;
if (npz->p_flags & PF_DJGPP_FILE)
err = errno_djgpp(err);
ECX = (long) err;
}
static void set_no_error(void)
{
EAX = ECX = 0L;
}
static void set_eax_return(DWORD reg_eax)
{
EAX = reg_eax;
ECX = 0L;
}
/*
** SYSEMX functions returns:
**
** CARRY_ON : error, set carry-bit
** CARRY_OFF: no error, clear carry-bit
** CARRY_NON: do nothing
*/
/* oldbrk_eax sbrk(inc_edx) ; err:eax=-1 */
static int sys_emx00_sbrk(void)
{
EAX = getmem(EDX, npz);
return CARRY_NON;
}
/* eax=0 brk(newbrk_edx) ; err:eax=-1 */
static int sys_emx01_brk(void)
{
if (EDX <= npz->brk_value)
EAX = -1L;
else if ((EAX = getmem(EDX - npz->brk_value, npz)) != -1L)
EAX = 0L;
return CARRY_NON;
}
/* maxbrk_eax ulimit(cmd_ecx,newlimit_edx) errno:ecx */
static int sys_emx02_ulimit(void)
{
if (ECX == 3L) {
FREEMEMINFO fm;
GetFreeMemInfo(&fm);
set_eax_return(fm.LargestFree + npz->brk_value);
} else
set_ecx_error(EMX_EINVAL);
return CARRY_NON;
}
/* emx special: void vmstat() */
static int sys_emx03_vmstat(void)
{
return CARRY_NON;
}
/* eax=filepermmask umask(edx) ; err:- */
static int sys_emx04_umask(void)
{
EAX = EDX;
return CARRY_NON;
}
/* eax getpid(void) err:- */
static int sys_emx05_getpid(void)
{
EAX = (DWORD) npz->pid;
return CARRY_NON;
}
/*
** eax = spawnve(proc_env *edx) err:carry errno:eax
*/
static int sys_emx06_spawn(void)
{
int i, ret;
PROCESS_ENV pe;
static char filename[260];
char **argp = NULL, **envp = NULL;
char *envmem = NULL, *argmem = NULL;
char *s;
/* get process data, check mode */
cpy32_16(DS, EDX, &pe, (DWORD) sizeof(PROCESS_ENV));
pe.mode &= 0xff;
if (pe.mode >= P_SESSION) { /* OS/2 modes */
EAX = EMX_EINVAL;
return CARRY_ON;
}
/* get memory for args and environment (env must para aligned) */
if ((argp = (char **) malloc((pe.arg_count + 1) * sizeof(char *))) == NULL
|| (envp = (char **) malloc((pe.env_count + 1) * sizeof(char *))) == NULL
|| (argmem = (char *) malloc((pe.arg_size + 1) & ~1)) == NULL
|| (envmem = (char *) malloc((pe.env_size + 20) & ~1)) == NULL
) {
printf("argmem,envmem to large a:%d e:%d\n", pe.arg_size, pe.env_size);
if (argp != NULL)
free(argp);
if (envp != NULL)
free(envp);
if (argmem != NULL)
free(argmem);
if (envmem != NULL)
free(envmem);
EAX = EMX_E2BIG;
return CARRY_ON;
}
/* get args from user ds, built arg-vector */
cpy32_16(DS, pe.arg_off, argmem, (DWORD) pe.arg_size);
s = argmem;
for (i = 0; i < (int) pe.arg_count; i++) {
s++; /* skip flag bits */
argp[i] = s;
s += (strlen(argp[i]) + 1);
}
argp[i] = NULL;
/* get env from user ds, built env-vector */
s = (char *) (((int)envmem + 15) & ~15); /* segment align */
cpy32_16(DS, pe.env_off, s, (DWORD) pe.env_size);
s[pe.env_size] = 0; /* for dos exec */
s[pe.env_size+1] = 0;
for (i = 0; i < (int) pe.env_count; i++) {
envp[i] = s;
s += (strlen(envp[i]) + 1);
}
envp[i] = NULL;
/* get filename */
strcpy32_16(DS, pe.fname_off, filename);
/* load a.out prg */
ret = exec32(pe.mode, filename, pe.arg_count, argp, pe.env_count, envp);
/* if error, try a real-mode prg */
if (ret == EMX_ENOEXEC) {
ret = realmode_prg(filename, argp, envp);
if (pe.mode == P_OVERLAY && ret != -1)
do_exit4c(0); /* close current emx program */
}
free(argmem);
free(envmem);
free(argp);
free(envp);
/* check error and return */
if (ret) {
EAX = (DWORD) ret;
return CARRY_ON;
} else
return CARRY_OFF;
}
static int sys_emx07_sigreturn(void)
{
signal_handler_returned();
return CARRY_NON;
}
/* eax ptrace(ebx,edi,edx,ecx) err:ecx!=0 eax=-1 */
static int sys_emx08_ptrace(void)
{
int error;
DWORD data;
if ((error = do_ptrace(BX, DI, EDX, ECX, &data)) != 0)
set_ecx_error(error);
else
set_eax_return(data);
return CARRY_NON;
}
/* eax=child_id wait(status_edx) ; errno:ecx */
static int sys_emx09_wait(void)
{
int ret;
unsigned status;
if ((ret = sys_wait(&status)) != -1) {
EDX = (DWORD) status;
set_eax_return((DWORD) (unsigned) ret);
} else
set_ecx_error(EMX_ESRCH);
return CARRY_NON;
}
#define RUN_VCPI 0x0001L
#define RUN_XMS 0x0002L
#define RUN_VDISK 0x0004L
#define RUN_DESQVIEW 0x0008L
#define RUN_287 0x0010L
#define RUN_387 0x0020L
#define RUN_486 0x0040L
#define RUN_DPMI09 0x0080L
#define RUN_DPMI10 0x0100L
#define RUN_OS2 0x0200L
#define RUN_T_OPT 0x0400L
#define RUN_AC_OPT 0x0800L
#define RUN_RSX 0x1000L
/* get emx-version ; err:- */
static int sys_emx0a_version(void)
{
DWORD run_info;
run_info = RUN_RSX | RUN_AC_OPT; /* RSX | data executable bit */
if (copro)
run_info |= RUN_387; /* with emu */
if (dpmi10)
run_info |= RUN_DPMI10;
else
run_info |= RUN_DPMI09;
/* enable gcc -pipe for emx 0.8x */
if (opt_os2)
run_info |= RUN_OS2;
EAX = can_run_emx;
EBX = run_info;
ECX = 0L;
EDX = 0L;
return CARRY_NON;
}
/* eax_pages memavail(void) ; err:- */
static int sys_emx0b_memavail(void)
{
FREEMEMINFO fm;
GetFreeMemInfo(&fm);
EAX = fm.MaxUnlockedPages;
return CARRY_NON;
}
/* (*prevh) signal(signo_ecx,address_edx) err:eax=-1 */
static int sys_emx0c_signal(void)
{
EAX = sys_signal ((int)ECX, EDX);
return CARRY_NON;
}
/* eax=0 kill(id_edx,signo_ecx) errno:ecx eax=-1 */
static int sys_emx0d_kill(void)
{
NEWPROCESS *p;
if (!(p = find_process((unsigned) EDX))) {
set_ecx_error(EMX_ESRCH);
return CARRY_NON;
} else if (send_signal(p, (int) (long) ECX)) {
set_ecx_error(EMX_EINVAL);
return CARRY_NON;
} else
set_no_error();
/* switch, if child */
if (p->pptr->pid == npz->pid) {
p->p_status = PS_RUN;
switch_context(p);
}
return CARRY_NON;
}
/* eax raise(ecx) errno:ecx eax=-1 */
static int sys_emx0e_raise(void)
{
if (send_signal(npz, CX))
set_ecx_error(EMX_EINVAL);
return CARRY_NON;
}
/* oldflags uflags(mask=ecx,new=edx) ;; bits 0-1 emx,SysV,BSD signals */
static int sys_emx0f_uflags(void)
{
EAX = npz->uflags;
npz->uflags &= ~ECX;
npz->uflags |= EDX;
return CARRY_NON;
}
/* void unwind(void) err:no */
static int sys_emx10_unwind(void)
{
return CARRY_NON;
}
/* core(handle_ebx) err:carry errno */
static int sys_emx11_core(void)
{
CONVERT1_BX_HANDLE ;
write_core(BX, npz);
EAX = 0;
return CARRY_OFF;
}
/* portaccess(ecx,edx) ecx=first edx=last, err:cy errno:eax */
static int sys_emx12_portaccess(void)
{
/* dpmi-server must allow this */
ECX = 0L; /* first port */
EDX = 0x3ffL; /* last port */
EAX = 0L;
return CARRY_OFF;
}
/* eax memaccess(Start=ebx,End=ecx,Flags=edx) err:carry errno:eax */
/* under DPMI it's better to used a different segment */
/* memaccess destroy protection -> limit 0xffffffff */
/* must use wrap-around to access memory */
static int sys_emx13_memaccess(void)
{
if ((opt_memaccess || (npz->options & OPT_MEMACCESS))
&& EBX <= 0xFFFFFL && ECX <= 0xFFFFFL) {
if (!dpmi10) {
/*
UINT sel;
DWORD screen_base;
if (SegToSel((UINT)(EBX >> 4), &sel))
screen_base = EBX;
else
GetBaseAddress(sel, &screen_base);
EAX = screen_base - npz->memaddress;
*/
EAX = EBX - npz->memaddress;
}
else
EAX = EBX + DPMI_PRG_DATA;
return CARRY_OFF;
} else {
EAX = EMX_EINVAL;
return CARRY_ON;
}
}
int sysemx_ioctl(int dos_handle, ARGUSER request, ARGUSER arg)
{
int attr, ret;
if ((attr = rm_ioctl_getattr(dos_handle)) == -1)
return -EMX_EBADF;
if (request >= TCGETA && request <= TCFLSH) {
if (dos_handle == 0 && (attr & 128)) { /* keyboard handle */
return kbd_ioctl((unsigned)request, arg);
} else /* others not supported */
return -EMX_EBADF;
}
else if (request == FIONREAD) {
if (dos_handle == 0 && (attr & 128) && (npz->p_flags & PF_TERMIO))
ret = kbd_ioctl((unsigned)request, arg);
else { /* others: 1=ready 0=not */
ret = rm_ioctl_select_in(dos_handle);
store32(npz->data32sel, arg, (long) ret);
ret = 0;
}
return ret;
}
else if (request == FGETHTYPE) {
long temp;
if (!(attr & 128))
temp = HT_FILE;
else if (attr & 3)
temp = HT_DEV_CON;
else if (attr & 4)
temp = HT_DEV_NUL;
else if (attr & 8)
temp = HT_DEV_CLK;
else
temp = HT_DEV_OTHER;
store32(DS, arg, temp);
return 0;
}
else
return -EMX_EINVAL;
}
/*
** eax = ioctl2(ebx,ecx,edx) errno:ecx eax=-1
*/
static int sys_emx14_ioctl(void)
{
int ret = sys_ioctl((int)EBX, ECX, EDX);
if (ret < 0)
set_ecx_error(-ret);
else
set_eax_return(ret);
return CARRY_NON;
}
/* eax=sec alarm(sec_edx) err:no */
static int sys_emx15_alarm(void)
{
if (time_tic < npz->time_alarm) /* there seconds left */
EAX = (npz->time_alarm - time_tic) * 182 / 10;
else
EAX = 0;
if (EDX == 0) /* clear alarm */
npz->time_alarm = 0;
else /* set alarm */
npz->time_alarm = time_tic + EDX * 182 / 10;
return CARRY_NON;
}
/* no syscall; internal */
static int sys_emx16_internal(void)
{
return CARRY_NON;
}
/*
** return ramaining clock tics
*/
static DWORD sleep_until(DWORD timel)
{
for (;;) {
if (time_reached(timel))
return 0;
if (npz->sig_raised & ~npz->sig_blocked)
return (timel - time_tic - 1);
schedule();
}
}
/* eax=0 sleep(edx) err:no */
static int sys_emx17_sleep(void)
{
EAX = sleep_until(time_tic + EDX * 182 / 10) * 10 / 182;
return CARRY_NON;
}
/*
** chsize(handle_ebx, lenght_edx) err:carry eax=errno
*/
static int sys_emx18_chsize(void)
{
CONVERT1_BX_HANDLE;
if (rm_lseek(BX, EDX, SEEK_SET) == -1L || rm_write(BX, iobuf, 0) == -1) {
EAX = (DWORD) doserror_to_errno(_doserrno);
return CARRY_ON;
}
EAX = 0;
return CARRY_OFF;
}
/* eax fcntl(handle ebx,req ecx,arg edx) errno:ecx */
static int sys_emx19_fcntl(void)
{
int fd = (int) (long) EBX;
struct file *filp;
if (fd >= N_FILES)
return -EMX_EBADF;
if (!(filp = npz->filp[fd]))
return -EMX_EBADF;
switch ((int)(long)ECX) {
case F_GETFL:
set_eax_return(filp->f_flags);
break;
case F_SETFL:
filp->f_flags &= ~(FCNTL_NDELAY | FCNTL_APPEND);
filp->f_flags |= EDX & (FCNTL_NDELAY | FCNTL_APPEND);
set_no_error();
break;
case F_GETFD:
set_eax_return(FD_ISSET(fd, &npz->close_on_exec));
break;
case F_SETFD:
if (EDX & 1)
FD_SET(fd, &npz->close_on_exec);
else
FD_CLR(fd, &npz->close_on_exec);
set_no_error();
break;
default:
set_ecx_error(EMX_EINVAL);
break;
}
return CARRY_NON;
}
/* eax pipe(edx,ecx) errno:ecx*/
static int sys_emx1a_pipe(void)
{
int ret = sys_pipe(ECX, EDX);
if (ret)
set_ecx_error(-ret);
else
set_no_error();
return CARRY_NON;
}
/* eax fsync(ebx) errno:ecx */
static int sys_emx1b_fsync(void)
{
set_ecx_error(EMX_EMSDOS);
return CARRY_NON;
}
/* eax fork(void) errno:ecx */
static int sys_emx1c_fork(void)
{
int ret;
if ((ret = sys_fork()) < 0)
set_ecx_error(-ret);
else
set_eax_return(ret);
return CARRY_NON;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -