diff --git a/loader/dos/dosmod.c b/loader/dos/dosmod.c index f80a8b3a5e6..fb7da7f4dd2 100644 --- a/loader/dos/dosmod.c +++ b/loader/dos/dosmod.c @@ -150,11 +150,38 @@ void cb_handler(int sig) signal(sig,cb_handler); } +int send_signal(void) +{ + int ret=sig_pend; sig_pend=0; + if (!ret) { + if (sig_alrm) { + ret=SIGALRM; sig_alrm--; + } else { + ret=SIGUSR2; sig_cb--; + } + } + if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1; + if (sig_fatal) return 1; + return 0; +} + +int send_enter_reply(int ret) +{ + if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1; + if (XWRITE(1,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1; + switch (ret&0xff) { + case DOSMOD_SIGNAL: + return send_signal(); + } + return 0; +} + int main(int argc,char**argv) { int mfd=open(argv[0],O_RDWR); struct timeval tim; - int func,ret; + mprot_info mpr; + int func,ret,idle; off_t fofs=0; pid_t ppid=getppid(); @@ -200,43 +227,69 @@ int main(int argc,char**argv) set_timer(&tim); #endif /* report back to the main program that we're ready */ - ret=2; /* dosmod protocol revision */ + ret=3; /* dosmod protocol revision */ XWRITE(1,&ret,sizeof(ret)); /* context exchange loop */ + idle=0; do { - if (XREAD(0,&func,sizeof(func))!=sizeof(func)) return 1; + if (idle) { + while (1) { + int res; + /* parent is idle, transmit any signals (particularly SIGALRM) */ + if (sig_pend||sig_alrm||sig_cb) { + ret=DOSMOD_SIGNAL; + if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1; + ret=send_signal(); + if (ret) return ret; + break; + } + res = read(0,&func,sizeof(func)); + if (res==sizeof(func)) + break; + if (res==-1) { + if (errno==EINTR) + continue; + perror("dosmod read"); + return 1; + } + if (res) /* don't print the EOF condition */ + fprintf(stderr,"dosmod read only %d of %d bytes.\n",res,sizeof(func)); + return 1; + } + ret=DOSMOD_LEFTIDLE; + if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1; + idle--; + } else + if (XREAD(0,&func,sizeof(func))!=sizeof(func)) return 1; if (func<0) break; switch (func) { - case DOSMOD_SET_TIMER: + case DOSMOD_SET_TIMER: /* rev 1 */ if (XREAD(0,&tim,sizeof(tim))!=sizeof(tim)) return 1; set_timer(&tim); /* no response */ break; - case DOSMOD_GET_TIMER: + case DOSMOD_GET_TIMER: /* rev 1 */ get_timer(&tim); if (XWRITE(1,&tim,sizeof(tim))!=sizeof(tim)) return 1; break; - case DOSMOD_ENTER: + case DOSMOD_MPROTECT: /* rev 3 */ + if (XREAD(0,&mpr,sizeof(mpr))!=sizeof(mpr)) return 1; + mprotect(mpr.addr,mpr.len,mpr.prot); + /* no response */ + break; + case DOSMOD_ENTERIDLE: /* rev 3 */ + idle++; + break; + case DOSMOD_LEAVEIDLE: /* rev 3 */ + break; + case DOSMOD_ENTER: /* rev 0 */ default: if (XREAD(0,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1; if (sig_pend||sig_alrm||sig_cb) ret=DOSMOD_SIGNAL; else ret=vm86plus(func,&VM86); - if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1; - if (XWRITE(1,&VM86,sizeof(VM86))!=sizeof(VM86)) return 1; - switch (ret&0xff) { - case DOSMOD_SIGNAL: - ret=sig_pend; sig_pend=0; - if (!ret) { - if (sig_alrm) { - ret=SIGALRM; sig_alrm--; - } else { - ret=SIGUSR2; sig_cb--; - } - } - if (XWRITE(1,&ret,sizeof(ret))!=sizeof(ret)) return 1; - if (sig_fatal) return 1; - break; - } + + ret=send_enter_reply(ret); + if (ret) return ret; } } while (1); return 0; diff --git a/loader/dos/dosmod.h b/loader/dos/dosmod.h index ee9d9f3c14b..155a91c3f84 100644 --- a/loader/dos/dosmod.h +++ b/loader/dos/dosmod.h @@ -4,7 +4,17 @@ #define DOSMOD_ENTER 0x01 /* VM86_ENTER */ #define DOSMOD_SET_TIMER 0x10 #define DOSMOD_GET_TIMER 0x11 +#define DOSMOD_MPROTECT 0x12 +#define DOSMOD_ENTERIDLE 0x13 +#define DOSMOD_LEAVEIDLE 0x14 -#define DOSMOD_SIGNAL 0x00 /* VM86_SIGNAL */ +#define DOSMOD_SIGNAL 0x00 /* VM86_SIGNAL */ +#define DOSMOD_LEFTIDLE 0x10 + +typedef struct { + void *addr; + size_t len; + int prot; +} mprot_info; #endif