diff options
Diffstat (limited to 'emu/Hp')
| -rw-r--r-- | emu/Hp/NOTE | 1 | ||||
| -rw-r--r-- | emu/Hp/asm-s800.s | 113 | ||||
| -rw-r--r-- | emu/Hp/cmd.c | 205 | ||||
| -rw-r--r-- | emu/Hp/devaudio.c | 506 | ||||
| -rw-r--r-- | emu/Hp/devfs.c | 1 | ||||
| -rw-r--r-- | emu/Hp/emu | 107 | ||||
| -rw-r--r-- | emu/Hp/mkfile | 50 | ||||
| -rw-r--r-- | emu/Hp/mkfile-Hp | 13 | ||||
| -rw-r--r-- | emu/Hp/os.c | 591 |
9 files changed, 1587 insertions, 0 deletions
diff --git a/emu/Hp/NOTE b/emu/Hp/NOTE new file mode 100644 index 00000000..3f1041ea --- /dev/null +++ b/emu/Hp/NOTE @@ -0,0 +1 @@ +this, like Irix, lacks deveia diff --git a/emu/Hp/asm-s800.s b/emu/Hp/asm-s800.s new file mode 100644 index 00000000..865c0b2b --- /dev/null +++ b/emu/Hp/asm-s800.s @@ -0,0 +1,113 @@ +; +; /* +; * To get lock routine, compile this into a .s, then SUBSTITUTE +; * a LOAD AND CLEAR WORD instruction for the load and store of +; * l->key. +; * +; */ +; typedef struct Lock { +; int key; +; int pid; +; } Lock; +; +; int +; mutexlock(Lock *l) +; { +; int key; +; +; key = l->key; +; l->key = 0; +; return key != 0; +; } + + .LEVEL 1.1 + + .SPACE $TEXT$,SORT=8 + .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=0x2c,CODE_ONLY,SORT=24 +mutexlock + .PROC + .CALLINFO FRAME=0,ARGS_SAVED + .ENTRY +; SUBSTITUTED LDW 0(%r26),%r31 +; SUBSTITUTED STWS %r0,0(%r26) + LDCWS 0(%r26),%r31 ; SUBSTITUTED + COMICLR,= 0,%r31,%r28 + LDI 1,%r28 + .EXIT + BV,N %r0(%r2) + .PROCEND + +; +; JIT help +; + .SPACE $TEXT$,SORT=8 + .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=0x2c,CODE_ONLY,SORT=24 +calldata + .PROC + .CALLINFO CALLER,FRAME=16,SAVE_RP + .ENTRY + STW %r2,-20(%r30) + LDO 64(%r30),%r30 + ADDIL LR'dataptr-$global$,%r27 + LDW RR'dataptr-$global$(%r1),%r31 + BLE 0(%sr5,%r31) + COPY %r31,%r2 + LDW -84(%r30),%r2 + BV %r0(%r2) + .EXIT + LDO -64(%r30),%r30 + .PROCEND + + .SPACE $PRIVATE$ + .SUBSPA $SHORTBSS$ +dataptr .COMM 4 + .SUBSPA $SHORTDATA$,QUAD=1,ALIGN=8,ACCESS=0x1f,SORT=24 +dyncall + .WORD $$dyncall + .EXPORT calldata + .EXPORT dyncall + .IMPORT $$dyncall,MILLICODE + + .SPACE $TEXT$ + .SUBSPA $CODE$ + .SPACE $PRIVATE$,SORT=16 + .SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=0x1f,SORT=16 + .SPACE $TEXT$ + .SUBSPA $CODE$ + .EXPORT mutexlock,ENTRY,PRIV_LEV=3,ARGW0=GR,RTNVAL=GR + + .code +; segflush(addr,len) + .proc + .callinfo + .export segflush,entry +segflush + .enter + ldsid (0,%arg0),%r1 + mtsp %r1,%sr0 + ldo -1(%arg1),%arg1 + copy %arg0,%arg2 + copy %arg1,%arg3 + fdc %arg1(0,%arg0) + +loop1 + addib,>,n -16,%arg1,loop1 + fdc %arg1(0,%arg0) + fdc 0(0,%arg0) + sync + fic %arg3(%sr0,%arg2) +loop2 + addib,>,n -16,%arg3,loop2 + fic %arg3(%sr0,%arg2) + fic 0(%sr0,%arg2) + sync + nop + nop + nop + nop + nop + nop + nop + .leave + .procend + .end diff --git a/emu/Hp/cmd.c b/emu/Hp/cmd.c new file mode 100644 index 00000000..97e303ac --- /dev/null +++ b/emu/Hp/cmd.c @@ -0,0 +1,205 @@ +#include <sys/types.h> +#include <signal.h> +#include <pwd.h> +#include <sys/resource.h> +#include <sys/wait.h> +#include <fcntl.h> + +#include "dat.h" +#include "fns.h" +#include "error.h" + +enum +{ + Debug = 0 +}; + +/* + * os-specific devcmd support. + * this version should be reasonably portable across Unix systems. + */ +typedef struct Targ Targ; +struct Targ +{ + int fd[2]; /* fd[0] is standard input, fd[1] is standard output */ + char** args; + char* dir; + int pid; + int wfd; /* child writes errors that occur after the fork or on exec */ + int uid; + int gid; +}; + +extern int gidnobody; +extern int uidnobody; + +static int +childproc(Targ *t) +{ + int i, nfd; + + if(Debug) + print("devcmd: '%s'", t->args[0]); + + nfd = getdtablesize(); + for(i = 0; i < nfd; i++) + if(i != t->fd[0] && i != t->fd[1] && i != t->wfd) + close(i); + + dup2(t->fd[0], 0); + dup2(t->fd[1], 1); + dup2(t->fd[1], 2); + close(t->fd[0]); + close(t->fd[1]); + + if(t->gid != -1){ + if(setgid(t->gid) < 0 && getegid() == 0){ + fprint(t->wfd, "can't set gid %d: %s", t->gid, strerror(errno)); + _exit(1); + } + } + + if(t->uid != -1){ + if(setuid(t->uid) < 0 && geteuid() == 0){ + fprint(t->wfd, "can't set uid %d: %s", t->uid, strerror(errno)); + _exit(1); + } + } + + if(t->dir != nil && chdir(t->dir) < 0){ + fprint(t->wfd, "can't chdir to %s: %s", t->dir, strerror(errno)); + _exit(1); + } + + signal(SIGPIPE, SIG_DFL); + + execvp(t->args[0], t->args); + if(Debug) + print("execvp: %s\n",strerror(errno)); + fprint(t->wfd, "exec failed: %s", strerror(errno)); + + _exit(1); +} + +void* +oscmd(char **args, int nice, char *dir, int *rfd, int *sfd) +{ + Dir *d; + Targ *t; + int r, fd0[2], fd1[2], wfd[2], n, pid; + + t = mallocz(sizeof(*t), 1); + if(t == nil) + return nil; + + fd0[0] = fd0[1] = -1; + fd1[0] = fd1[1] = -1; + wfd[0] = wfd[1] = -1; + if(pipe(fd0) < 0 || pipe(fd1) < 0 || pipe(wfd) < 0) + goto Error; + if(fcntl(wfd[1], F_SETFD, FD_CLOEXEC) < 0) /* close on exec to give end of file on success */ + goto Error; + + t->fd[0] = fd0[0]; + t->fd[1] = fd1[1]; + t->wfd = wfd[1]; + t->args = args; + t->dir = dir; + t->gid = up->env->gid; + if(t->gid == -1) + t->gid = gidnobody; + t->uid = up->env->uid; + if(t->uid == -1) + t->uid = uidnobody; + + signal(SIGCHLD, SIG_DFL); + switch(pid = fork()) { + case -1: + goto Error; + case 0: + setpgrp(); + if(nice) + oslopri(); + childproc(t); + _exit(1); + default: + t->pid = pid; + if(Debug) + print("cmd pid %d\n", t->pid); + break; + } + + close(fd0[0]); + close(fd1[1]); + close(wfd[1]); + + n = read(wfd[0], up->genbuf, sizeof(up->genbuf)-1); + close(wfd[0]); + if(n > 0){ + close(fd0[1]); + close(fd1[0]); + free(t); + up->genbuf[n] = 0; + if(Debug) + print("oscmd: bad exec: %q\n", up->genbuf); + error(up->genbuf); + return nil; + } + + *sfd = fd0[1]; + *rfd = fd1[0]; + return t; + +Error: + r = errno; + if(Debug) + print("oscmd: %q\n",strerror(r)); + close(fd0[0]); + close(fd0[1]); + close(fd1[0]); + close(fd1[1]); + close(wfd[0]); + close(wfd[1]); + error(strerror(r)); + return nil; +} + +int +oscmdkill(void *a) +{ + Targ *t = a; + + if(Debug) + print("kill: %d\n", t->pid); + return kill(-t->pid, SIGTERM); +} + +int +oscmdwait(void *a, char *buf, int n) +{ + Targ *t = a; + int s; + + if(waitpid(t->pid, &s, 0) == -1){ + if(Debug) + print("wait error: %d [in %d] %q\n", t->pid, getpid(), strerror(errno)); + return -1; + } + if(WIFEXITED(s)){ + if(WEXITSTATUS(s) == 0) + return snprint(buf, n, "%d 0 0 0 ''", t->pid); + return snprint(buf, n, "%d 0 0 0 'exit: %d'", t->pid, WEXITSTATUS(s)); + } + if(WIFSIGNALED(s)){ + if(WTERMSIG(s) == SIGTERM || WTERMSIG(s) == SIGKILL) + return snprint(buf, n, "%d 0 0 0 killed", t->pid); + return snprint(buf, n, "%d 0 0 0 'signal: %d'", t->pid, WTERMSIG(s)); + } + return snprint(buf, n, "%d 0 0 0 'odd status: 0x%x'", t->pid, s); +} + +void +oscmdfree(void *a) +{ + free(a); +} diff --git a/emu/Hp/devaudio.c b/emu/Hp/devaudio.c new file mode 100644 index 00000000..c26143e3 --- /dev/null +++ b/emu/Hp/devaudio.c @@ -0,0 +1,506 @@ +#include "dat.h" +#include "fns.h" +#include "error.h" + +#include <sys/audio.h> + + +enum{ + Qdir, + Qaudio, + Qaudioctl, /* deprecated */ + Qvolume, + + Fmono = 1, + Fin = 2, + Fout = 4, + Fhearn = 8, + + Vaudio = 0, + Vsynth, + Vcd, + Vline, + Vmic, + Vspeaker, + Vtreb, + Vbass, + Vspeed, + Vbits, + Vchans, + Venc, + Nvol, + + Epcm = 0, + Eulaw, + Ealaw, + Nenc, + + Speed = 44100, + Ncmd = 50, /* max volume command words */ +}; +Dirtab audiotab[]={ + "audio", {Qaudio, 0}, 0, 0666, + "audioctl", {Qaudioctl, 0}, 0, 0666, + "volume", {Qvolume, 0}, 0, 0666, +}; + +typedef struct Audiodev Audiodev; + +struct Audiodev { + int fd; + int swab; + int repl1; + int repl2; +}; + +static struct +{ + QLock; /* XXX maybe we should use this guy! */ + int rivol[Nvol]; /* right/left input/output volumes */ + int livol[Nvol]; + int rovol[Nvol]; + int lovol[Nvol]; +} audio; + +static struct +{ + char* name; + int flag; + int ilval; /* initial values */ + int irval; +} volumes[] = +{ +/*[Vaudio]*/ "audio", Fout, 50, 50, +/*[Vsynth]*/ "synth", Fin|Fout, 0, 0, +/*[Vcd]*/ "cd", Fin|Fout, 0, 0, +/*[Vline]*/ "line", Fin|Fout, 0, 0, +/*[Vmic]*/ "mic", Fin|Fout|Fmono, 0, 0, +/*[Vspeaker]*/ "speaker", Fout|Fmono, 0, 0, + +/*[Vtreb]*/ "treb", Fout, 50, 50, +/*[Vbass]*/ "bass", Fout, 50, 50, + +/*[Vspeed]*/ "speed", Fin|Fout|Fmono, Speed, Speed, +/*[Vbits]*/ "bits", Fin|Fout|Fmono|Fhearn, 16, 16, +/*[Vchans]*/ "chans", Fin|Fout|Fmono|Fhearn, 2, 2, +/*[Venc]*/ "enc", Fin|Fout|Fmono|Fhearn, Epcm, Epcm, + 0 +}; + +static char *encname[] = +{ +/*Epcm*/ "pcm", +/*Eulaw*/ "ulaw", +/*Ealaw*/ "alaw", +}; + +static char Evolume[] = "illegal volume specifier"; + +static void +resetlevel(void) +{ + int i; + + for(i=0; volumes[i].name; i++) { + audio.lovol[i] = volumes[i].ilval; + audio.rovol[i] = volumes[i].irval; + audio.livol[i] = volumes[i].ilval; + audio.rivol[i] = volumes[i].irval; + } +} + +/* Start OS-dependant code */ +static int +doioctl(int fd, int whim, void *data, char *what) +{ + char ebuf[ERRMAX]; + int r, n; + + osenter(); + r = ioctl(fd, whim, data); + osleave(); + if (r < 0) { + n = snprint(ebuf, ERRMAX, "ioctl %s: ", what); + oserrstr(ebuf+n, sizeof ebuf-n); + error(ebuf); + } + return r; +} + +static void +setlevels(Audiodev *a) +{ + struct audio_describe au; + struct audio_gain gain; + int i, x; + +/* XXX todo: simulate it with a data conversion routine (could also do swab...) */ + if (audio.lovol[Venc] == Epcm && audio.lovol[Vbits] != 16) { + audio.lovol[Vbits] = 16; + error("pcm must be 16 bits"); + } + if (audio.lovol[Vchans] != 1 && audio.lovol[Vchans] != 2) { + audio.lovol[Vchans] = 1; + error("bad number of channels"); + } + + doioctl(a->fd, AUDIO_DESCRIBE, &au, "describe"); + doioctl(a->fd, AUDIO_SET_SAMPLE_RATE, audio.lovol[Vspeed], "rate"); /* what if input != output??? */ + doioctl(a->fd, AUDIO_SET_CHANNELS, audio.lovol[Vchans], "channels"); + + switch (audio.lovol[Venc]) { + default: + case Epcm: + x = AUDIO_FORMAT_LINEAR16BIT; + break; + case Eulaw: + x = AUDIO_FORMAT_ULAW; + break; + case Ealaw: + x = AUDIO_FORMAT_ALAW; + break; + } + doioctl(a->fd, AUDIO_SET_DATA_FORMAT, x, "set format"); + + x = 0; + if (audio.lovol[Vspeaker] != 0 || audio.rovol[Vspeaker] != 0) + x |= AUDIO_OUT_SPEAKER; + if (audio.lovol[Vaudio] != 0 || audio.rovol[Vaudio] != 0) + x |= AUDIO_OUT_HEADPHONE; + if (audio.lovol[Vline] != 0 || audio.rovol[Vline] != 0) + x |= AUDIO_OUT_LINE; + doioctl(a->fd, AUDIO_SET_OUTPUT, x, "set output"); + + x = 0; + if (audio.livol[Vline] != 0 || audio.rivol[Vline] != 0) + x |= AUDIO_IN_LINE; + if (audio.livol[Vmic] != 0 || audio.rivol[Vmic] != 0 || x == 0) /* must set at least one */ + x |= AUDIO_IN_MIKE; + doioctl(a->fd, AUDIO_SET_INPUT, x, "set input"); + +/* XXX todo: get the gains right. should scale 0-100 into min-max (as in struct audio_describe au) */ +/* doioctl(a->fd, AUDIO_GET_GAINS, &gain, "get gains"); */ + gain.channel_mask = AUDIO_CHANNEL_LEFT|AUDIO_CHANNEL_RIGHT; + for (i = 0; i < 2; i++) { + gain.cgain[i].receive_gain = au.min_receive_gain; + gain.cgain[i].monitor_gain = au.min_monitor_gain; + gain.cgain[i].transmit_gain = au.max_transmit_gain; + } + doioctl(a->fd, AUDIO_SET_GAINS, &gain, "set gains"); +} + +static char * +audiofname(int isctl) +{ + if (isctl) + return "/dev/audioCtl"; + else + return "/dev/audio"; +} + +static void +audioswab(uchar *p, int n) +{ + int x; + + /* XXX slow; should check for 16bit mode; should be combined with format conversion; etc */ + while (n >= 2) { + x = p[0]; + p[0] = p[1]; + p[1] = x; + p +=2; + n -=2; + } +} +/* End OS-dependant code */ + +static void +audioinit(void) +{ + resetlevel(); +} + +static Chan* +audioattach(char* spec) +{ + return devattach('A', spec); +} + +static int +audiowalk(Chan* c, char* name) +{ + return devwalk(c, name, audiotab, nelem(audiotab), devgen); +} + +static void +audiostat(Chan* c, char* db) +{ + devstat(c, db, audiotab, nelem(audiotab), devgen); +} + +static Chan* +audioopen(Chan *c, int omode) +{ + Audiodev *a; + long path; + char ebuf[ERRMAX]; + + path = c->qid.path & ~CHDIR; + if (path != Qdir){ +/* XXX Irix portability? (multiple opens -- how to match ctl with data???) */ + a = malloc(sizeof(Audiodev)); + if(a == nil) + error(Enomem); + if (waserror()) { + free(a); + nexterror(); + } + a->fd = open(audiofname(path != Qaudio), omode&7); + if(a->fd < 0) + oserror(); + if (path == Qaudio) + setlevels(a); + c->aux = a; + poperror(); + } + return devopen(c, omode, audiotab, nelem(audiotab), devgen); +} + +static void +audioclose(Chan* c) +{ + Audiodev *a; + + a = c->aux; + if (a != nil) { + close(a->fd); + free(a); + } +} + +static long +audioread(Chan* c, void *ua, long n, vlong offset) +{ + Audiodev *a; + char buf[300], ebuf[ERRMAX]; + int liv, riv, lov, rov; + int j, m; + long path; + + a = c->aux; + path = (c->qid.path & ~CHDIR); + switch(path){ + case Qdir: + return devdirread(c, a, n, audiotab, nelem(audiotab), devgen); + case Qaudio: + osenter(); + n = read(a->fd, ua, n); + osleave(); + if (n < 0) + oserror(); + audioswab(ua, n); /* XXX what if n is odd? also, only if 16 bit... must fix portability */ + break; + case Qaudioctl: + case Qvolume: + j = 0; + buf[0] = 0; + for(m=0; volumes[m].name; m++){ + if ((volumes[m].flag & Fhearn) && path == Qvolume) + continue; + liv = audio.livol[m]; + riv = audio.rivol[m]; + lov = audio.lovol[m]; + rov = audio.rovol[m]; + j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name); + if(m == Venc) + j += snprint(buf+j, sizeof(buf)-j, " %s", encname[lov]); + else if((volumes[m].flag & Fmono) || liv==riv && lov==rov){ + if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov) + j += snprint(buf+j, sizeof(buf)-j, " %d", liv); + else{ + if(volumes[m].flag & Fin) + j += snprint(buf+j, sizeof(buf)-j, " in %d", liv); + if(volumes[m].flag & Fout) + j += snprint(buf+j, sizeof(buf)-j, " out %d", lov); + } + }else{ + if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov && riv==rov) + j += snprint(buf+j, sizeof(buf)-j, " left %d right %d", + liv, riv); + else{ + if(volumes[m].flag & Fin) + j += snprint(buf+j, sizeof(buf)-j, " in left %d right %d", + liv, riv); + if(volumes[m].flag & Fout) + j += snprint(buf+j, sizeof(buf)-j, " out left %d right %d", + lov, rov); + } + } + j += snprint(buf+j, sizeof(buf)-j, "\n"); + } + return readstr(offset, ua, n, buf); + default: + n=0; + break; + } + return n; +} + +static long +audiowrite(Chan* c, char *ua, long n, vlong offset) +{ + Audiodev *a; + long m, n0; + int i, nf, v, left, right, in, out; + char buf[255], *field[Ncmd], ebuf[ERRMAX], *p; + + a = c->aux; + switch(c->qid.path & ~CHDIR){ + case Qaudio: + n &= ~1; + audioswab(ua, n); /* XXX VERY BAD BUG; THIS CHANGES THE CALLER'S DATA */ + osenter(); + n = write(a->fd, ua, n); + osleave(); + if (n < 0) + oserror(); + break; + case Qaudioctl: + case Qvolume: + v = Vaudio; + left = 1; + right = 1; + in = 1; + out = 1; + if(n > sizeof(buf)-1) + n = sizeof(buf)-1; + memmove(buf, ua, n); + buf[n] = '\0'; + + nf = getfields(buf, field, Ncmd, 1, " \t\n"); + for(i = 0; i < nf; i++){ + /* + * a number is volume + */ + if(field[i][0] >= '0' && field[i][0] <= '9') { + m = strtoul(field[i], &p, 10); + if (p != nil && *p == 'k') + m *= 1000; + if(left && out) + audio.lovol[v] = m; + if(left && in) + audio.livol[v] = m; + if(right && out) + audio.rovol[v] = m; + if(right && in) + audio.rivol[v] = m; + setlevels(a); + goto cont0; + } + + for(m=0; volumes[m].name; m++) { + if(strcmp(field[i], volumes[m].name) == 0) { + v = m; + in = 1; + out = 1; + left = 1; + right = 1; + goto cont0; + } + } + + if(strcmp(field[i], "reset") == 0) { + resetlevel(); + setlevels(a); + goto cont0; + } + if(strcmp(field[i], "in") == 0) { + in = 1; + out = 0; + goto cont0; + } + if(strcmp(field[i], "out") == 0) { + in = 0; + out = 1; + goto cont0; + } + if(strcmp(field[i], "left") == 0) { + left = 1; + right = 0; + goto cont0; + } + if(strcmp(field[i], "right") == 0) { + left = 0; + right = 1; + goto cont0; + } + if(strcmp(field[i], "rate") == 0) { + v = Vspeed; + in = 1; + out = 1; + left = 1; + right = 1; + goto cont0; + } + if(strcmp(field[i], "chan") == 0) { /* XXX egregious backward compatibility hack */ + v = Vchans; + in = 1; + out = 1; + left = 1; + right = 1; + goto cont0; + } + if(v == Venc) { + if (strcmp(field[i], "pcm") == 0) { + audio.lovol[v] = Epcm; + goto cont0; + } + if (strcmp(field[i], "ulaw") == 0) { + audio.lovol[v] = Eulaw; + goto cont0; + } + if (strcmp(field[i], "alaw") == 0) { + audio.lovol[v] = Ealaw; + goto cont0; + } + } + if(v == Vchans) { + if (strcmp(field[i], "mono") == 0) { + audio.lovol[v] = 1; + goto cont0; + } + if (strcmp(field[i], "stereo") == 0) { + audio.lovol[v] = 2; + goto cont0; + } + } + error(Evolume); + break; + cont0:; + } + break; + default: + error(Ebadusefd); + } + return n; +} + +Dev audiodevtab = { + 'A', + "audio", + + audioinit, + audioattach, + devclone, + audiowalk, + audiostat, + audioopen, + devcreate, + audioclose, + audioread, + devbread, + audiowrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/emu/Hp/devfs.c b/emu/Hp/devfs.c new file mode 100644 index 00000000..9017c3fc --- /dev/null +++ b/emu/Hp/devfs.c @@ -0,0 +1 @@ +#include "devfs-posix.c" diff --git a/emu/Hp/emu b/emu/Hp/emu new file mode 100644 index 00000000..88bb23e4 --- /dev/null +++ b/emu/Hp/emu @@ -0,0 +1,107 @@ +dev + root + cons + env + mnt + pipe + prog + prof + srv + dup + ssl + cap + fs + cmd cmd + indir + + draw + pointer + snarf + + ip ipif-posix ipaux +# eia +# audio audio + audio + mem + +lib + interp + tk + freetype + math + draw + + memlayer + memdraw + keyring + sec + mp + + 9 + +link + +mod + sys + draw + + tk + math + srv srv + keyring + loader + freetype + +port + alloc + cache + chan + dev + dial + dis + discall + env + error + errstr + exception + exportfs + inferno + latin1 + main + parse + pgrp + print + proc + qio + random + sysfile + uqid + +code + +init + emuinit + +root + /dev / + /fd / + /prog / + /net / + /net.alt / + /chan / + /nvfs / + /env / +# /chan +# /dev +# /dis +# /env +# /n +# /net +# /nvfs / +# /prog +# /icons +# /osinit.dis +# /dis/emuinit.dis +# /dis/lib/auth.dis +# /dis/lib/ssl.dis +# /n/local / diff --git a/emu/Hp/mkfile b/emu/Hp/mkfile new file mode 100644 index 00000000..ef7c6db1 --- /dev/null +++ b/emu/Hp/mkfile @@ -0,0 +1,50 @@ +SYSTARG=Hp +OBJTYPE=s800 +<../../mkconfig +SYSTARG=Hp +OBJTYPE=s800 + +#Configurable parameters + +CONF=emu #default configuration +CONFLIST=emu +CLEANCONFLIST= + +INSTALLDIR=$ROOT/$SYSTARG/$OBJTYPE/bin #path of directory where kernel is installed + +#end configurable parameters + +<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE #set vars based on target system + +<| $SHELLNAME ../port/mkdevlist $CONF #sets $IP, $DEVS, $PORT, $LIBS + +OBJ=\ + asm-$OBJTYPE.$O\ + os.$O\ + win-x11.$O\ + $CONF.root.$O\ + lock.$O\ + $DEVS\ + $PORT\ + +HFILES=\ + +CFLAGS='-DROOT="'$ROOT'"' -DEMU -I. -I../port -I$ROOT/$SYSTARG/$OBJTYPE/include -I$ROOT/include -I$ROOT/libinterp $CTHREADFLAGS $CFLAGS $EMUOPTIONS +SYSLIBS= -lm -lX11 -lcma +KERNDATE=`{$NDATE} + +default:V: $O.$CONF + +<../port/portmkfile + +$O.$CONF: $OBJ $CONF.c $CONF.root.h $LIBFILES + $CC $CFLAGS '-DKERNDATE='$KERNDATE $CONF.c + $LD $LDFLAGS -o $target $OBJ $CONF.$O $LIBFILES $SYSLIBS + +install:V: $O.$CONF + cp $O.$CONF $INSTALLDIR/$CONF + +devaudio.$O: devaudio.c + $CC $CFLAGS devaudio.c + +devfs.$O: ../port/devfs-posix.c diff --git a/emu/Hp/mkfile-Hp b/emu/Hp/mkfile-Hp new file mode 100644 index 00000000..37c625db --- /dev/null +++ b/emu/Hp/mkfile-Hp @@ -0,0 +1,13 @@ +# +# architecture-dependent files for Hp +# + +TARGFILES=asm-Hp-s800.$O\ + devfs-posix.$O\ + devip.$O\ + ipif-posix.$O\ + os-Hp.$O\ + win-x11.$O\ + devaudio-Hp.$O\ + srv.$O\ + lock.$O\ diff --git a/emu/Hp/os.c b/emu/Hp/os.c new file mode 100644 index 00000000..a371ac50 --- /dev/null +++ b/emu/Hp/os.c @@ -0,0 +1,591 @@ +#include <pthread.h> +#include <signal.h> +#include "dat.h" +#include "fns.h" +#include "error.h" +#include <sys/socket.h> +#include <time.h> +#include <sys/time.h> +#include <termios.h> +#include <pwd.h> +#include <errno.h> + +enum +{ + BUNCHES = 5000, + DELETE = 0x7F +}; +char *hosttype = "Hp"; + + +static pthread_key_t prdakey; + +extern int dflag; + +Lock mulock = {1, 0}; + +ulong +_tas(ulong *l) +{ + ulong v; + + while(!(mutexlock(&mulock))) + pthread_yield(); + + v = *l; + if(v == 0) + *l = 1; + mulock.key = 1; + return v; +} + +static ulong erendezvous(void*, ulong); + + +void +osblock(void) +{ + erendezvous(up, 0); +} + +void +osready(Proc *p) +{ + erendezvous(p, 0); +} + + +void +pexit(char *msg, int t) +{ + Osenv *e; + + lock(&procs.l); + if(up->prev) + up->prev->next = up->next; + else + procs.head = up->next; + + if(up->next) + up->next->prev = up->prev; + else + procs.tail = up->prev; + unlock(&procs.l); + + e = up->env; + if(e != nil) { + closefgrp(e->fgrp); + closepgrp(e->pgrp); + closeegrp(e->egrp); + closesigs(e->sigs); + } + free(up->prog); + free(up); + pthread_exit(0); +} + +void +trapBUS(int signo, siginfo_t *info, void *context) +{ + if(info) + print("trapBUS: signo: %d code: %d addr: %lx\n", + info->si_signo, info->si_code, info->si_addr); + else + print("trapBUS: no info\n"); + disfault(nil, "Bus error"); +} + +void +trapUSR1(void) +{ + int intwait; + + intwait = up->intwait; + up->intwait = 0; /* clear it to let proc continue in osleave */ + + if(up->type != Interp) /* Used to unblock pending I/O */ + return; + + if(intwait == 0) /* Not posted so it's a sync error */ + disfault(nil, Eintr); /* Should never happen */ +} + +void +trapILL(void) +{ + disfault(nil, "Illegal instruction"); +} + +void +trapSEGV(void) +{ + disfault(nil, "Segmentation violation"); +} + +sigset_t set; +setsigs() +{ + struct sigaction act; + + memset(&act, 0 , sizeof(act)); + sigemptyset(&set); + + act.sa_handler=SIG_IGN; + if(sigaction(SIGPIPE, &act, nil)) + panic("can't ignore sig pipe"); + + if(sigaddset(&set,SIGUSR1)== -1) + panic("sigaddset SIGUSR1"); + + if(sigaddset(&set,SIGUSR2)== -1) + panic("sigaddset SIGUSR2"); + + /* For the correct functioning of devcmd in the + * face of exiting slaves + */ + if(sflag == 0) { + act.sa_handler=trapBUS; + act.sa_flags|=SA_SIGINFO; + if(sigaction(SIGBUS, &act, nil)) + panic("sigaction SIGBUS"); + act.sa_handler=trapILL; + if(sigaction(SIGILL, &act, nil)) + panic("sigaction SIGILL"); + act.sa_handler=trapSEGV; + if(sigaction(SIGSEGV, &act, nil)) + panic("sigaction SIGSEGV"); + if(sigaddset(&set,SIGINT)== -1) + panic("sigaddset"); + } + if(sigprocmask(SIG_BLOCK,&set,nil)!= 0) + panic("sigprocmask"); +} + +static void * +tramp(void *v) +{ + struct Proc *Up; + pthread_t thread; + struct sigaction oldact; + + setsigs(); + if(sigaction(SIGBUS, nil, &oldact)) + panic("sigaction failed"); + if(oldact.sa_handler!=trapBUS && sflag==0) + panic("3rd old act sa_handler"); + + if(pthread_setspecific(prdakey,v)) { + print("set specific data failed in tramp\n"); + pthread_exit(0); + } + Up = v; + thread = pthread_self(); + Up->sigid = cma_thread_get_unique(&thread); + /* attempt to catch signals again */ + setsigs(); + Up->func(Up->arg); + pexit("", 0); +} + +pthread_t active_threads[BUNCHES]; /* this should be more than enuf */ + +int +kproc(char *name, void (*func)(void*), void *arg, int flags) +{ + pthread_t thread; + pthread_attr_t attr; + int id; + Proc *p; + Pgrp *pg; + Fgrp *fg; + Egrp *eg; + struct sigaction oldact; + + p = newproc(); + + if(flags & KPDUPPG) { + pg = up->env->pgrp; + incref(&pg->r); + p->env->pgrp = pg; + } + if(flags & KPDUPFDG) { + fg = up->env->fgrp; + incref(&fg->r); + p->env->fgrp = fg; + } + if(flags & KPDUPENVG) { + eg = up->env->egrp; + incref(&eg->r); + p->env->egrp = eg; + } + + p->env->uid = up->env->uid; + p->env->gid = up->env->gid; + kstrdup(&p->env->user, up->env->user); +; + + strcpy(p->text, name); + + p->func = func; + p->arg = arg; + + lock(&procs.l); + if(procs.tail != nil) { + p->prev = procs.tail; + procs.tail->next = p; + } + else { + procs.head = p; + p->prev = nil; + } + procs.tail = p; + unlock(&procs.l); + if((pthread_attr_create(&attr))== -1) + panic("pthread_attr_create failed"); + + errno=0; + pthread_attr_setsched(&attr,SCHED_OTHER); + if(errno) + panic("pthread_attr_setsched failed"); + + if(pthread_create(&thread, attr, tramp, p)) + panic("thr_create failed\n"); + if(sigaction(SIGBUS, nil, &oldact)) + panic("sigaction failed"); + if(oldact.sa_handler!=trapBUS && sflag == 0) + panic("2nd old act sa_handler"); + + if((id=cma_thread_get_unique(&thread))>=BUNCHES) + panic("id too big"); + active_threads[id]=thread; + return id; +} + +void +oshostintr(Proc *p) +{ + pthread_cancel(active_threads[p->sigid]); +} + +void +oslongjmp(void *regs, osjmpbuf env, int val) +{ + USED(regs); + siglongjmp(env, val); +} + +struct termios tinit; + +static void +termset(void) +{ + struct termios t; + + tcgetattr(0, &t); + tinit = t; + t.c_lflag &= ~(ICANON|ECHO|ISIG); + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + tcsetattr(0, TCSANOW, &t); +} + +static void +termrestore(void) +{ + tcsetattr(0, TCSANOW, &tinit); +} + +void +cleanexit(int x) +{ + USED(x); + + if(up->intwait) { + up->intwait = 0; + return; + } + + if(dflag == 0) + termrestore(); + + kill(0, SIGKILL); + exit(0); +} + +void +osreboot(char *file, char **argv) +{ + if(dflag == 0) + termrestore(); + execvp(file, argv); + panic("reboot failure"); +} + +int gidnobody= -1, uidnobody= -1; + +void +getnobody() +{ + struct passwd *pwd; + + if(pwd = getpwnam("nobody")) { + uidnobody = pwd->pw_uid; + gidnobody = pwd->pw_gid; + } +} + +static pthread_mutex_t rendezvouslock; + +void +libinit(char *imod) +{ + struct passwd *pw; + struct Proc *Up; + struct sigaction oldact; + int ii; + int retval; + int *pidptr; + char sys[64]; + + cma_init(); + setsid(); + /* mulock.key = 1; */ /* initialize to unlock */ + if(pthread_mutex_init(&rendezvouslock,pthread_mutexattr_default)) + panic("pthread_mutex_init"); + + gethostname(sys, sizeof(sys)); + kstrdup(&ossysname, sys); + getnobody(); + + if(dflag == 0) + termset(); + + setsigs(); + if(sigaction(SIGBUS, nil, &oldact)) { + panic("sigaction failed"); + } + if(oldact.sa_handler!=trapBUS && sflag == 0) + panic("1st old act sa_handler"); + + if(pthread_keycreate(&prdakey,NULL)) + print("keycreate failed\n"); + + Up = newproc(); + if(pthread_setspecific(prdakey,Up)) + panic("set specific thread data failed\n"); + + pw = getpwuid(getuid()); + if(pw != nil) + kstrdup(&eve, pw->pw_name); + else + print("cannot getpwuid\n"); + + up->env->uid = getuid(); + up->env->gid = getgid(); + emuinit(imod); +} + +int +readkbd(void) +{ + int n; + char buf[1]; + + n = read(0, buf, sizeof(buf)); + if(n != 1) { + print("keyboard close (n=%d, %s)\n", n, strerror(errno)); + pexit("keyboard thread", 0); + } + + switch(buf[0]) { + case '\r': + buf[0] = '\n'; + break; + case DELETE: + cleanexit(0); + break; + } + return buf[0]; +} + +enum +{ + NHLOG = 7, + NHASH = (1<<NHLOG) +}; + +typedef struct Tag Tag; +struct Tag +{ + void* tag; + ulong val; + int pid; + Tag* hash; + Tag* free; + pthread_cond_t cv; +}; + +static Tag* ht[NHASH]; +static Tag* ft; + +static ulong +erendezvous(void *tag, ulong value) +{ + int h; + ulong rval; + Tag *t, *f, **l; + int ii=0; + + h = (ulong)tag & (NHASH-1); + + if(pthread_mutex_lock(&rendezvouslock)) + panic("pthread_mutex_lock"); + + l = &ht[h]; + for(t = *l; t; t = t->hash) { + if(t->tag == tag) { + rval = t->val; + t->val = value; + t->tag = 0; + if(pthread_mutex_unlock(&rendezvouslock)) + panic("pthread_mutex_unlock"); + if(pthread_cond_signal(&(t->cv))) + panic("pthread_cond_signal"); + return rval; + } + } + + t = ft; + if(t == 0) { + t = malloc(sizeof(Tag)); + if(t == 0) + panic("rendezvous: no memory"); + if(pthread_cond_init(&(t->cv),pthread_condattr_default)) { + print("pthread_cond_init (errno: %s) \n", strerror(errno)); + panic("pthread_cond_init"); + } + } else + ft = t->free; + + t->tag = tag; + t->val = value; + t->hash = *l; + *l = t; + + while(t->tag) + pthread_cond_wait(&(t->cv),&rendezvouslock); + + rval = t->val; + for(f = *l; f; f = f->hash){ + if(f == t) { + *l = f->hash; + break; + } + l = &f->hash; + } + t->free = ft; + ft = t; + if(pthread_mutex_unlock(&rendezvouslock)) + panic("pthread_mutex_unlock"); + + return rval; +} + + +/* + * Return an abitrary millisecond clock time + */ +long +osmillisec(void) +{ + static long sec0 = 0, usec0; + struct timeval t; + + if(gettimeofday(&t,(struct timezone*)0)<0) + return(0); + if(sec0==0) { + sec0 = t.tv_sec; + usec0 = t.tv_usec; + } + return((t.tv_sec-sec0)*1000+(t.tv_usec-usec0+500)/1000); +} + +/* + * Return the time since the epoch in nanoseconds and microseconds + * The epoch is defined at 1 Jan 1970 + */ +vlong +osnsec(void) +{ + struct timeval t; + + gettimeofday(&t, nil); + return (vlong)t.tv_sec*1000000000L + t.tv_usec*1000; +} + +vlong +osusectime(void) +{ + struct timeval t; + + gettimeofday(&t, nil); + return (vlong)t.tv_sec * 1000000 + t.tv_usec; +} + + +int +osmillisleep(ulong milsec) +{ + struct timespec time; + time.tv_sec = milsec/1000; + time.tv_nsec= (milsec%1000)*1000000; + if(pthread_delay_np(&time)== -1) + ; /* might be interrupted */ + return 0; +} + +Proc * +getup(void) +{ + void *vp; + + vp=nil; + pthread_getspecific(prdakey,&vp); + return(vp); +} + +ulong +getcallerpc(void *arg) +{ + return 0 ; +} + +void +osyield(void) +{ + pthread_yield(); +} + +void +ospause(void) +{ + int s; + + for(;;) { + switch(s=sigwait(&set)) { + case SIGUSR1: + trapUSR1(); + case SIGINT: + cleanexit(0); + default: + print("signal: %d %s\n",s, strerror(errno)); + panic("sigwait"); + } + } +} + +void +oslopri(void) +{ + /* TO DO */ +} |
