diff options
Diffstat (limited to 'emu/Linux')
| -rw-r--r-- | emu/Linux/arm-tas-v5.S | 18 | ||||
| -rw-r--r-- | emu/Linux/arm-tas-v7.S | 30 | ||||
| -rw-r--r-- | emu/Linux/asm-386.S | 51 | ||||
| -rw-r--r-- | emu/Linux/asm-arm.S | 62 | ||||
| -rw-r--r-- | emu/Linux/asm-mips.S | 28 | ||||
| -rw-r--r-- | emu/Linux/asm-power.S | 61 | ||||
| -rw-r--r-- | emu/Linux/asm-spim.S | 29 | ||||
| -rw-r--r-- | emu/Linux/audio-oss.c | 441 | ||||
| -rw-r--r-- | emu/Linux/cmd.c | 213 | ||||
| -rw-r--r-- | emu/Linux/deveia.c | 44 | ||||
| -rw-r--r-- | emu/Linux/devfs.c | 26 | ||||
| -rw-r--r-- | emu/Linux/emu | 106 | ||||
| -rw-r--r-- | emu/Linux/emu-g | 101 | ||||
| -rw-r--r-- | emu/Linux/emu-wrt | 111 | ||||
| -rw-r--r-- | emu/Linux/mk-wrt | 8 | ||||
| -rw-r--r-- | emu/Linux/mkfile | 53 | ||||
| -rw-r--r-- | emu/Linux/mkfile-386 | 0 | ||||
| -rw-r--r-- | emu/Linux/mkfile-arm | 2 | ||||
| -rw-r--r-- | emu/Linux/mkfile-mips | 0 | ||||
| -rw-r--r-- | emu/Linux/mkfile-power | 0 | ||||
| -rw-r--r-- | emu/Linux/os.c | 304 | ||||
| -rw-r--r-- | emu/Linux/segflush-386.c | 11 | ||||
| -rw-r--r-- | emu/Linux/segflush-arm.c | 14 | ||||
| -rw-r--r-- | emu/Linux/segflush-mips.S | 16 | ||||
| -rw-r--r-- | emu/Linux/segflush-power.c | 34 | ||||
| -rw-r--r-- | emu/Linux/segflush-spim.S | 16 |
26 files changed, 1779 insertions, 0 deletions
diff --git a/emu/Linux/arm-tas-v5.S b/emu/Linux/arm-tas-v5.S new file mode 100644 index 0000000..4bd13c2 --- /dev/null +++ b/emu/Linux/arm-tas-v5.S @@ -0,0 +1,18 @@ + + .file "arm-tas-v5.S" +/* + * ulong _tas(ulong*); + */ + .align 2 + .global _tas + .type _tas, %function +_tas: + @ args = 0, pretend = 0, frame = 0 + @ frame_needed = 0, uses_anonymous_args = 0 + @ link register save eliminated. + @ lr needed for prologue + mov r3, #1 + mov r1, r0 + swp r0, r3, [r1] + bx lr + .size _tas, .-_tas diff --git a/emu/Linux/arm-tas-v7.S b/emu/Linux/arm-tas-v7.S new file mode 100644 index 0000000..584b31f --- /dev/null +++ b/emu/Linux/arm-tas-v7.S @@ -0,0 +1,30 @@ + .file "arm-tas-v7.S" +#ifndef ARMv7 +#define DMB mcr p15, 0, r0, c7, c10, 5 +#else +#define DMB dmb +#endif +.align 2 +.global _tas +.type _tas, %function +_tas: + @ args = 0, pretend = 0, frame = 0 + @ frame_needed = 0, uses_anonymous_args = 0 + @ link register save eliminated. + @ lr needed for prologue + DMB + mov r1, r0 + mov r2, #0xaa +tas1: + ldrex r0, [r1] + cmp r0, #0 + bne lockbusy + strex r3, r2, [r1] + cmp r3, #0 + bne tas1 + DMB + bx lr +lockbusy: + clrex + bx lr + .size _tas, .-_tas diff --git a/emu/Linux/asm-386.S b/emu/Linux/asm-386.S new file mode 100644 index 0000000..fe5ce6c --- /dev/null +++ b/emu/Linux/asm-386.S @@ -0,0 +1,51 @@ + .file "asm-Linux-386.S" + .text + +/* + * umult(ulong m1, ulong m2, ulong *hi) + */ + + .type umult,@function + .global umult +umult: + pushl %ebp + movl %esp, %ebp + pushl %ebx + + movl 8(%ebp), %eax + movl 12(%ebp), %ebx + mull %ebx + movl 16(%ebp), %ebx + movl %edx, (%ebx) + + popl %ebx + popl %ebp + ret + + .type FPsave,@function + .global FPsave +FPsave: + pushl %ebp + movl %esp, %ebp + movl 8(%ebp), %eax + fstenv (%eax) + popl %ebp + ret + + .type FPrestore,@function + .global FPrestore +FPrestore: + pushl %ebp + movl %esp, %ebp + movl 8(%ebp), %eax + fldenv (%eax) + popl %ebp + ret + + .type _tas,@function + .globl _tas +_tas: + movl $1, %eax + movl 4(%esp), %ecx + xchgl %eax, 0(%ecx) + ret diff --git a/emu/Linux/asm-arm.S b/emu/Linux/asm-arm.S new file mode 100644 index 0000000..5446dde --- /dev/null +++ b/emu/Linux/asm-arm.S @@ -0,0 +1,62 @@ + .file "asm-Linux-arm.S" + .text + +/* + * ulong umult(ulong m1, ulong m2, ulong *hi) + */ + + .align 2 + .global umult + .type umult, %function +umult: + @ args = 0, pretend = 0, frame = 12 + @ frame_needed = 1, uses_anonymous_args = 0 + mov ip, sp + stmfd sp!, {fp, ip, lr, pc} + sub fp, ip, #4 + sub sp, sp, #12 + str r0, [fp, #-16] + str r1, [fp, #-20] + str r2, [fp, #-24] + ldr r1, [fp, #-16] + ldr r2, [fp, #-20] + umull r0, r3, r1, r2 + ldr r1, [fp, #-24] + str r3, [r1] + ldmea fp, {fp, sp, pc} + .size umult, .-umult + +/* + * void FPsave(void*); + */ + + .align 2 + .global FPsave + .type FPsave, %function +FPsave: + @ args = 0, pretend = 0, frame = 4 + @ frame_needed = 1, uses_anonymous_args = 0 + mov ip, sp + stmfd sp!, {fp, ip, lr, pc} + sub fp, ip, #4 + sub sp, sp, #4 + str r0, [fp, #-16] + ldmea fp, {fp, sp, pc} + .size FPsave, .-FPsave + +/* + * void FPrestore(void*); + */ + .align 2 + .global FPrestore + .type FPrestore, %function +FPrestore: + @ args = 0, pretend = 0, frame = 4 + @ frame_needed = 1, uses_anonymous_args = 0 + mov ip, sp + stmfd sp!, {fp, ip, lr, pc} + sub fp, ip, #4 + sub sp, sp, #4 + str r0, [fp, #-16] + ldmea fp, {fp, sp, pc} + .size FPrestore, .-FPrestore diff --git a/emu/Linux/asm-mips.S b/emu/Linux/asm-mips.S new file mode 100644 index 0000000..d2780f6 --- /dev/null +++ b/emu/Linux/asm-mips.S @@ -0,0 +1,28 @@ +#include <sys/asm.h> +#include <sys/regdef.h> +#include <asm/cachectl.h> + +LEAF(FPsave) + cfc1 t0, $31 + sw t0, 0(a0) /* a0 is argument */ + j $31 + END(FPsave) + +LEAF(FPrestore) + lw t0, 0(a0) /* a0 is argument */ + ctc1 t0, $31 + j $31 + END(FPrestore) + +LEAF(_tas) + .set noreorder +1: + ll v0,0(a0) /* a0 is argument */ + or t1, v0, 1 + sc t1,0(a0) + beq t1,zero,1b + nop + j $31 /* lock held */ + nop + .set reorder + END(_tas) diff --git a/emu/Linux/asm-power.S b/emu/Linux/asm-power.S new file mode 100644 index 0000000..7187f93 --- /dev/null +++ b/emu/Linux/asm-power.S @@ -0,0 +1,61 @@ + .align 2 + .global FPsave +FPsave: + stfd %f14,0*8(%r3) + stfd %f15,1*8(%r3) + stfd %f16,2*8(%r3) + stfd %f17,3*8(%r3) + stfd %f18,4*8(%r3) + stfd %f19,5*8(%r3) + stfd %f20,6*8(%r3) + stfd %f21,7*8(%r3) + stfd %f22,8*8(%r3) + stfd %f23,9*8(%r3) + stfd %f24,10*8(%r3) + stfd %f25,11*8(%r3) + stfd %f26,12*8(%r3) + stfd %f27,13*8(%r3) + stfd %f28,14*8(%r3) + stfd %f29,15*8(%r3) + stfd %f30,16*8(%r3) + stfd %f31,17*8(%r3) + blr + + .align 2 + .global FPrestore +FPrestore: + lfd %f14,0*8(%r3) + lfd %f15,1*8(%r3) + lfd %f16,2*8(%r3) + lfd %f17,3*8(%r3) + lfd %f18,4*8(%r3) + lfd %f19,5*8(%r3) + lfd %f20,6*8(%r3) + lfd %f21,7*8(%r3) + lfd %f22,8*8(%r3) + lfd %f23,9*8(%r3) + lfd %f24,10*8(%r3) + lfd %f25,11*8(%r3) + lfd %f26,12*8(%r3) + lfd %f27,13*8(%r3) + lfd %f28,14*8(%r3) + lfd %f29,15*8(%r3) + lfd %f30,16*8(%r3) + lfd %f31,17*8(%r3) + blr + + .align 2 + .global _tas +_tas: + sync + mr %r4, %r3 + addi %r5,0,0x1 +1: + lwarx %r3, 0, %r4 + cmpwi %r3, 0 + bne- 2f + stwcx. %r5, 0, %r4 + bne- 1b +2: + sync + blr diff --git a/emu/Linux/asm-spim.S b/emu/Linux/asm-spim.S new file mode 100644 index 0000000..77ae3d4 --- /dev/null +++ b/emu/Linux/asm-spim.S @@ -0,0 +1,29 @@ +#include <sys/asm.h> +#include <sys/regdef.h> +#include <asm/cachectl.h> + + +LEAF(FPsave) + cfc1 t0, $31 + sw t0, 0(a0) /* a0 is argument */ + j $31 + END(FPsave) + +LEAF(FPrestore) + lw t0, 0(a0) /* a0 is argument */ + ctc1 t0, $31 + j $31 + END(FPrestore) + +LEAF(_tas) + .set noreorder +1: + ll v0,0(a0) /* a0 is argument */ + or t1, v0, 1 + sc t1,0(a0) + beq t1,zero,1b + nop + j $31 /* lock held */ + nop + .set reorder + END(_tas) diff --git a/emu/Linux/audio-oss.c b/emu/Linux/audio-oss.c new file mode 100644 index 0000000..696e37c --- /dev/null +++ b/emu/Linux/audio-oss.c @@ -0,0 +1,441 @@ +#include "dat.h" +#include "fns.h" +#include "error.h" +#include "audio.h" +#include <sys/ioctl.h> +#include <sys/soundcard.h> + +#define Audio_Mic_Val SOUND_MIXER_MIC +#define Audio_Linein_Val SOUND_MIXER_LINE + +#define Audio_Speaker_Val SOUND_MIXER_PCM // SOUND_MIXER_VOLUME +#define Audio_Headphone_Val SOUND_MIXER_ALTPCM +#define Audio_Lineout_Val SOUND_MIXER_CD + +#define Audio_Pcm_Val AFMT_S16_LE +#define Audio_Ulaw_Val AFMT_MU_LAW +#define Audio_Alaw_Val AFMT_A_LAW + +#include "audio-tbls.c" +#define min(a,b) ((a) < (b) ? (a) : (b)) + +#define DEVAUDIO "/dev/dsp" +#define DEVMIXER "/dev/mixer" + +#define DPRINT if(1)print + +enum { + A_Pause, + A_UnPause, + A_In, + A_Out, +}; + +static struct { + int data; /* dsp data fd */ + int ctl; /* mixer fd */ + int pause; + QLock lk; +} afd = {.data = -1, .ctl = -1, .pause =A_UnPause }; + +static Audio_t av; +static QLock inlock; +static QLock outlock; + +static int audio_open(int); +static int audio_pause(int, int); +static int audio_set_info(int, Audio_d*, int); + +Audio_t* +getaudiodev(void) +{ + return &av; +} + +void +audio_file_init(void) +{ + audio_info_init(&av); +} + +void +audio_file_open(Chan *c, int omode) +{ + USED(c); + DPRINT("audio_file_open %d %d %x\n", afd.data, afd.ctl, omode); + qlock(&afd.lk); + if(waserror()){ + qunlock(&afd.lk); + nexterror(); + } + if(afd.data >= 0) + error(Einuse); + if(afd.ctl < 0){ + afd.ctl = open(DEVMIXER, ORDWR); + if(afd.ctl < 0) + oserror(); + } + afd.data = audio_open(omode); + if(afd.data < 0) + oserror(); + poperror(); + qunlock(&afd.lk); +} + +void +audio_file_close(Chan *c) +{ + USED(c); + DPRINT("audio_file_close %d %d\n", afd.data, afd.ctl); + qlock(&afd.lk); + if(waserror()){ + qunlock(&afd.lk); + nexterror(); + } + close(afd.data); + afd.data = -1; + qunlock(&afd.lk); + poperror(); +} + +long +audio_file_read(Chan *c, void *va, long count, vlong offset) +{ + long ba, status, chunk, total; + + USED(c); + USED(offset); + DPRINT("audio_file_read %d %d\n", afd.data, afd.ctl); + qlock(&inlock); + if(waserror()){ + qunlock(&inlock); + nexterror(); + } + + if(afd.data < 0) + error(Eperm); + + /* check block alignment */ + ba = av.in.bits * av.in.chan / Bits_Per_Byte; + + if(count % ba) + error(Ebadarg); + + if(!audio_pause(afd.data, A_UnPause)) + error(Eio); + + total = 0; + while(total < count){ + chunk = count - total; + status = read (afd.data, va + total, chunk); + if(status < 0) + error(Eio); + total += status; + } + + if(total != count) + error(Eio); + + poperror(); + qunlock(&inlock); + + return count; +} + +long +audio_file_write(Chan *c, void *va, long count, vlong offset) +{ + long status = -1; + long ba, total, chunk, bufsz; + + USED(c); + USED(offset); + DPRINT("audio_file_write %d %d\n", afd.data, afd.ctl); + qlock(&outlock); + if(waserror()){ + qunlock(&outlock); + nexterror(); + } + + if(afd.data < 0) + error(Eperm); + + /* check block alignment */ + ba = av.out.bits * av.out.chan / Bits_Per_Byte; + + if(count % ba) + error(Ebadarg); + + total = 0; + bufsz = av.out.buf * Audio_Max_Buf / Audio_Max_Val; + + if(bufsz == 0) + error(Ebadarg); + + while(total < count){ + chunk = min(bufsz, count - total); + status = write(afd.data, va, chunk); + if(status <= 0) + error(Eio); + total += status; + } + + poperror(); + qunlock(&outlock); + + return count; +} + +long +audio_ctl_write(Chan *c, void *va, long count, vlong offset) +{ + Audio_t tmpav = av; + int tfd; + + USED(c); + USED(offset); + tmpav.in.flags = 0; + tmpav.out.flags = 0; + + DPRINT ("audio_ctl_write %X %X\n", afd.data, afd.ctl); + if(!audioparse(va, count, &tmpav)) + error(Ebadarg); + + if(!canqlock(&inlock)) + error("device busy"); + if(waserror()){ + qunlock(&inlock); + nexterror(); + } + if(!canqlock(&outlock)) + error("device busy"); + if(waserror()){ + qunlock(&outlock); + nexterror(); + } + + /* DEVAUDIO needs to be open to issue an ioctl */ + tfd = afd.data; + if(tfd < 0){ + tfd = open(DEVAUDIO, O_RDONLY|O_NONBLOCK); + if(tfd < 0) + oserror(); + } + if(waserror()){ + if(tfd != afd.data) + close(tfd); + nexterror(); + } + + if(tmpav.in.flags & AUDIO_MOD_FLAG){ + if(!audio_pause(tfd, A_Pause)) + error(Ebadarg); + if(!audio_set_info(tfd, &tmpav.in, A_In)) + error(Ebadarg); + } + + poperror(); + if(tfd != afd.data) + close(tfd); + + tmpav.in.flags = 0; + av = tmpav; + + poperror(); + qunlock(&outlock); + poperror(); + qunlock(&inlock); + return count; +} + +/* Linux/OSS specific stuff */ + +static int +choosefmt(Audio_d *i) +{ + switch(i->bits){ + case 8: + switch(i->enc){ + case Audio_Alaw_Val: + return AFMT_A_LAW; + case Audio_Ulaw_Val: + return AFMT_MU_LAW; + case Audio_Pcm_Val: + return AFMT_U8; + } + break; + case 16: + if(i->enc == Audio_Pcm_Val) + return AFMT_S16_LE; + break; + } + return -1; +} + +static int +setvolume(int fd, int what, int left, int right) +{ + int can, v; + + if(ioctl(fd, SOUND_MIXER_READ_DEVMASK, &can) < 0) + can = ~0; + + DPRINT("setvolume fd%d %X can mix 0x%X (mask %X)\n", fd, what, (can & (1<<what)), can); + if(!(can & (1<<what))) + return 0; + v = left | (right<<8); + if(ioctl(afd.ctl, MIXER_WRITE(what), &v) < 0) + return 0; + return 1; +} + +static int +audio_set_info(int fd, Audio_d *i, int d) +{ + int status, arg; + int oldfmt, newfmt; + + USED(d); + DPRINT("audio_set_info (%d) %d %d\n", fd, afd.data, afd.ctl); + if(fd < 0) + return 0; + + /* sample rate */ + if(i->flags & AUDIO_RATE_FLAG){ + arg = i->rate; + if(ioctl(fd, SNDCTL_DSP_SPEED, &arg) < 0) + return 0; + } + + /* channels */ + if(i->flags & AUDIO_CHAN_FLAG){ + arg = i->chan; + if(ioctl(fd, SNDCTL_DSP_CHANNELS, &arg) < 0) + return 0; + } + + /* precision */ + if(i->flags & AUDIO_BITS_FLAG){ + arg = i->bits; + if(ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &arg) < 0) + return 0; + } + + /* encoding */ + if(i->flags & AUDIO_ENC_FLAG){ + ioctl(fd, SNDCTL_DSP_GETFMTS, &oldfmt); + + newfmt = choosefmt(i); + if(newfmt < 0) + return 0; + if(newfmt != oldfmt){ + status = ioctl(fd, SNDCTL_DSP_SETFMT, &arg); + DPRINT ("enc oldfmt newfmt %x status %d\n", oldfmt, newfmt, status); + } + } + + /* dev volume */ + if(i->flags & (AUDIO_LEFT_FLAG|AUDIO_VOL_FLAG)) + return setvolume(afd.ctl, i->dev, i->left, i->right); + + return 1; +} + +static int +audio_set_blocking(int fd) +{ + int val; + + if((val = fcntl(fd, F_GETFL, 0)) == -1) + return 0; + + val &= ~O_NONBLOCK; + + if(fcntl(fd, F_SETFL, val) < 0) + return 0; + + return 1; +} + +static int +audio_open(int omode) +{ + int fd; + + /* open non-blocking in case someone already has it open */ + /* otherwise we would block until they close! */ + switch (omode){ + case OREAD: + fd = open(DEVAUDIO, O_RDONLY|O_NONBLOCK); + break; + case OWRITE: + fd = open(DEVAUDIO, O_WRONLY|O_NONBLOCK); + break; + case ORDWR: + fd = open(DEVAUDIO, O_RDWR|O_NONBLOCK); + break; + } + + DPRINT("audio_open %d\n", fd); + if(fd < 0) + oserror(); + + /* change device to be blocking */ + if(!audio_set_blocking(fd)){ + close(fd); + error("cannot set blocking mode"); + } + + if(!audio_pause(fd, A_Pause)){ + close(fd); + error(Eio); + } + + /* set audio info */ + av.in.flags = ~0; + av.out.flags = ~0; + + if(!audio_set_info(fd, &av.in, A_In)){ + close(fd); + error(Ebadarg); + } + + av.in.flags = 0; + + /* tada, we're open, blocking, paused and flushed */ + return fd; +} + +static int +dspsync(int fd) +{ + return ioctl(fd, SNDCTL_DSP_RESET, NULL) >= 0 && + ioctl(fd, SNDCTL_DSP_SYNC, NULL) >= 0; +} + +static int +audio_pause(int fd, int f) +{ + int status; + +// DPRINT ("audio_pause (%d) %d %d\n", fd, afd.data, afd.ctl); + if(fd < 0) + return 0; + if(fd != afd.data) + return dspsync(fd); + qlock(&afd.lk); + if(afd.pause == f){ + qunlock(&afd.lk); + return 1; + } + if(waserror()){ + qunlock(&afd.lk); + nexterror(); + } + status = dspsync(afd.data); + if(status) + afd.pause = f; + poperror(); + qunlock(&afd.lk); + return status; +} diff --git a/emu/Linux/cmd.c b/emu/Linux/cmd.c new file mode 100644 index 0000000..0b8c960 --- /dev/null +++ b/emu/Linux/cmd.c @@ -0,0 +1,213 @@ +#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[3]; /* fd[0] is standard input, fd[1] is standard output, fd[2] is standard error */ + 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->fd[2] && i != t->wfd) + close(i); + + dup2(t->fd[0], 0); + dup2(t->fd[1], 1); + dup2(t->fd[2], 2); + close(t->fd[0]); + close(t->fd[1]); + close(t->fd[2]); + + /* should have an auth file to do host-specific authorisation? */ + 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 *fd) +{ + Targ *t; + int r, fd0[2], fd1[2], fd2[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; + fd2[0] = fd2[1] = -1; + wfd[0] = wfd[1] = -1; + if(pipe(fd0) < 0 || pipe(fd1) < 0 || pipe(fd2) < 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->fd[2] = fd2[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) + setpriority(PRIO_PROCESS, 0, 19); + 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(fd2[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]); + close(fd2[0]); + free(t); + up->genbuf[n] = 0; + if(Debug) + print("oscmd: bad exec: %q\n", up->genbuf); + error(up->genbuf); + return nil; + } + + fd[0] = fd0[1]; + fd[1] = fd1[0]; + fd[2] = fd2[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(fd2[0]); + close(fd2[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/Linux/deveia.c b/emu/Linux/deveia.c new file mode 100644 index 0000000..a1f0951 --- /dev/null +++ b/emu/Linux/deveia.c @@ -0,0 +1,44 @@ +/* + * Linux serial port definitions + */ + +static char *sysdev[] = { + "/dev/ttyS0", + "/dev/ttyS1", + "/dev/ttyS2", + "/dev/ttyS3", + "/dev/ttyS4", + "/dev/ttyS5", + "/dev/ttyS6", + "/dev/ttyS7", +}; + +#include <sys/ioctl.h> +#include "deveia-posix.c" +#include "deveia-bsd.c" + + +static struct tcdef_t bps[] = { + {0, B0}, + {50, B50}, + {75, B75}, + {110, B110}, + {134, B134}, + {150, B150}, + {200, B200}, + {300, B300}, + {600, B600}, + {1200, B1200}, + {1800, B1800}, + {2400, B2400}, + {4800, B4800}, + {9600, B9600}, + {19200, B19200}, + {38400, B38400}, + {57600, B57600}, + {115200, B115200}, + {230400, B230400}, + {460800, B460800}, + {-1, -1} +}; + diff --git a/emu/Linux/devfs.c b/emu/Linux/devfs.c new file mode 100644 index 0000000..d697d7b --- /dev/null +++ b/emu/Linux/devfs.c @@ -0,0 +1,26 @@ +#include "devfs-posix.c" + +#include <linux/hdreg.h> +#include <linux/fs.h> +#include <sys/ioctl.h> + +static vlong +osdisksize(int fd) +{ + uvlong u64; + long l; + struct hd_geometry geo; + + memset(&geo, 0, sizeof geo); + l = 0; + u64 = 0; +#ifdef BLKGETSIZE64 + if(ioctl(fd, BLKGETSIZE64, &u64) >= 0) + return u64; +#endif + if(ioctl(fd, BLKGETSIZE, &l) >= 0) + return l*512; + if(ioctl(fd, HDIO_GETGEO, &geo) >= 0) + return (vlong)geo.heads*geo.sectors*geo.cylinders*512; + return 0; +} diff --git a/emu/Linux/emu b/emu/Linux/emu new file mode 100644 index 0000000..3189240 --- /dev/null +++ b/emu/Linux/emu @@ -0,0 +1,106 @@ +dev + root + cons + env + mnt + pipe + prog + prof + srv + dup + ssl + cap + fs + cmd cmd + indir + + draw win-x11a + pointer + snarf + + ip ipif6-posix ipaux + eia +# audio audio-oss + mem + +lib + interp + tk + freetype + math + draw + + memlayer + memdraw + keyring + sec + mp + + 9 + +link + +mod + sys + draw + + tk + math + srv srv + keyring + crypt + ipints + loader + freetype + +port + alloc + cache + chan + dev + devtab + + 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 / + /prof / + /net / + /net.alt / + /chan / + /nvfs / + /env / + /gui / +# /dis +# /n +# /icons +# /osinit.dis +# /dis/emuinit.dis +# /dis/lib/auth.dis +# /dis/lib/ssl.dis +# /n/local / diff --git a/emu/Linux/emu-g b/emu/Linux/emu-g new file mode 100644 index 0000000..8df0b4c --- /dev/null +++ b/emu/Linux/emu-g @@ -0,0 +1,101 @@ +env + X11LIBS= +dev + root + cons + env + mnt + pipe + prog + prof + srv + dup + ssl + cap + fs + cmd cmd + indir + + ip ipif6-posix ipaux + eia +# audio audio + mem + +lib + interp + math + keyring + sec + mp + + 9 + +link + +mod + sys + math + srv srv + keyring + crypt + ipints + loader + +port + alloc + cache + chan + dev + devtab + + dial + dis + discall + env + error + errstr + exception + exportfs + inferno + latin1 + main + parse + pgrp + print + proc + qio + random + sysfile + uqid + +code + void setpointer(int x, int y){USED(x); USED(y);} + ulong strtochan(char *s){USED(s); return ~0;} + +init + emuinit + +root + /dev / + /fd / + /prog / + /prof / + /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/Linux/emu-wrt b/emu/Linux/emu-wrt new file mode 100644 index 0000000..0eac3af --- /dev/null +++ b/emu/Linux/emu-wrt @@ -0,0 +1,111 @@ +dev + root + cons + env + mnt + pipe + prog + prof + srv + dup + ssl + cap + fs + cmd cmd + indir + +# draw +# pointer +# snarf + + ip ipif6-posix ipaux +# eia +# audio audio + mem + +lib + interp +# tk +# freetype + math +# draw + +# memlayer +# memdraw + keyring + sec + mp + + 9 + +link + +mod + sys +# draw + +# tk + math + srv srv + keyring + crypt + ipints + 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 + int dontcompile = 1; + unsigned long strtochan(char *s) {return 0;} + +init + emuinit + +root + /dev / + /fd / + /prog / + /prof / + /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/Linux/mk-wrt b/emu/Linux/mk-wrt new file mode 100644 index 0000000..f301dde --- /dev/null +++ b/emu/Linux/mk-wrt @@ -0,0 +1,8 @@ +#!/bin/sh + +OPENWRT=$HOME/OpenWrt-SDK-Linux-i686-1 +INFERNO=/usr/inferno + +PATH=$OPENWRT/staging_dir_mipsel/bin:$INFERNO/Linux/386/bin:$PATH + +mk OBJTYPE=spim CONF=emu-wrt CONFLIST=emu-wrt SYSLIBS=-lm WIN= $* diff --git a/emu/Linux/mkfile b/emu/Linux/mkfile new file mode 100644 index 0000000..3b072d5 --- /dev/null +++ b/emu/Linux/mkfile @@ -0,0 +1,53 @@ +SYSTARG=Linux +<../../mkconfig +SYSTARG=Linux + +#Configurable parameters + +CONF=emu #default configuration +CONFLIST=emu +CLEANCONFLIST= + +INSTALLDIR=$ROOT/$SYSTARG/$OBJTYPE/bin #path of directory where kernel is installed + +#end configurable parameters + +X11LIBS= -lX11 -lXext # can remove or override using env section in config files + +<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE #set vars based on target system + +<| $SHELLNAME ../port/mkdevlist $CONF #sets $IP, $DEVS, $PORT, $LIBS +<mkfile-$OBJTYPE # sets $ARCHFILES + +OBJ=\ + asm-$OBJTYPE.$O\ + $ARCHFILES\ + os.$O\ + kproc-pthreads.$O\ + segflush-$OBJTYPE.$O\ + $CONF.root.$O\ + lock.$O\ + $DEVS\ + $PORT\ + +LIBNAMES=${LIBS:%=lib%.a} +#libs=${LIBS:%=$ROOT/$OBJDIR/lib/lib%.a} + +HFILES=\ + +CFLAGS='-DROOT="'$ROOT'"' -DEMU -I. -I../port -I$ROOT/$SYSTARG/$OBJTYPE/include -I$ROOT/include -I$ROOT/libinterp $CTHREADFLAGS $CFLAGS $EMUOPTIONS +SYSLIBS= $X11LIBS -lm -lpthread +KERNDATE=`{$NDATE} + +default:V: $O.$CONF + +$O.$CONF: $OBJ $CONF.c $CONF.root.h $LIBNAMES + $CC $CFLAGS '-DKERNDATE='$KERNDATE $CONF.c + $LD $LDFLAGS -o $target $OBJ $CONF.$O $LIBFILES $SYSLIBS + +install:V: $O.$CONF + cp $O.$CONF $INSTALLDIR/$CONF + +<../port/portmkfile + +devfs.$O: ../port/devfs-posix.c diff --git a/emu/Linux/mkfile-386 b/emu/Linux/mkfile-386 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/emu/Linux/mkfile-386 diff --git a/emu/Linux/mkfile-arm b/emu/Linux/mkfile-arm new file mode 100644 index 0000000..01cdd7c --- /dev/null +++ b/emu/Linux/mkfile-arm @@ -0,0 +1,2 @@ +ARCHFILES=\ + arm-tas-v7.$O\ diff --git a/emu/Linux/mkfile-mips b/emu/Linux/mkfile-mips new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/emu/Linux/mkfile-mips diff --git a/emu/Linux/mkfile-power b/emu/Linux/mkfile-power new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/emu/Linux/mkfile-power diff --git a/emu/Linux/os.c b/emu/Linux/os.c new file mode 100644 index 0000000..08b039d --- /dev/null +++ b/emu/Linux/os.c @@ -0,0 +1,304 @@ +#include <sys/types.h> +#include <time.h> +#include <termios.h> +#include <signal.h> +#include <pwd.h> +#include <sched.h> +#include <sys/resource.h> +#include <sys/wait.h> +#include <sys/time.h> + +#include <stdint.h> + +#include "dat.h" +#include "fns.h" +#include "error.h" + +#include <semaphore.h> + +#include <raise.h> + +/* glibc 2.3.3-NTPL messes up getpid() by trying to cache the result, so we'll do it ourselves */ +#include <sys/syscall.h> +#define getpid() syscall(SYS_getpid) + +enum +{ + DELETE = 0x7f, + CTRLC = 'C'-'@', + NSTACKSPERALLOC = 16, + X11STACK= 256*1024 +}; +char *hosttype = "Linux"; + +typedef sem_t Sem; + +extern int dflag; + +int gidnobody = -1; +int uidnobody = -1; +static struct termios tinit; + +static void +sysfault(char *what, void *addr) +{ + char buf[64]; + + snprint(buf, sizeof(buf), "sys: %s%#p", what, addr); + disfault(nil, buf); +} + +static void +trapILL(int signo, siginfo_t *si, void *a) +{ + USED(signo); + USED(a); + sysfault("illegal instruction pc=", si->si_addr); +} + +static int +isnilref(siginfo_t *si) +{ + return si != 0 && (si->si_addr == (void*)~(uintptr_t)0 || (uintptr_t)si->si_addr < 512); +} + +static void +trapmemref(int signo, siginfo_t *si, void *a) +{ + USED(a); /* ucontext_t*, could fetch pc in machine-dependent way */ + if(isnilref(si)) + disfault(nil, exNilref); + else if(signo == SIGBUS) + sysfault("bad address addr=", si->si_addr); /* eg, misaligned */ + else + sysfault("segmentation violation addr=", si->si_addr); +} + +static void +trapFPE(int signo, siginfo_t *si, void *a) +{ + char buf[64]; + + USED(signo); + USED(a); + snprint(buf, sizeof(buf), "sys: fp: exception status=%.4lux pc=%#p", getfsr(), si->si_addr); + disfault(nil, buf); +} + +static void +trapUSR1(int signo) +{ + int intwait; + + USED(signo); + + 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 +oslongjmp(void *regs, osjmpbuf env, int val) +{ + USED(regs); + siglongjmp(env, val); +} + +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); + error("reboot failure"); +} + +void +libinit(char *imod) +{ + struct sigaction act; + struct passwd *pw; + Proc *p; + char sys[64]; + + setsid(); + + gethostname(sys, sizeof(sys)); + kstrdup(&ossysname, sys); + pw = getpwnam("nobody"); + if(pw != nil) { + uidnobody = pw->pw_uid; + gidnobody = pw->pw_gid; + } + + if(dflag == 0) + termset(); + + memset(&act, 0, sizeof(act)); + act.sa_handler = trapUSR1; + sigaction(SIGUSR1, &act, nil); + + act.sa_handler = SIG_IGN; + sigaction(SIGCHLD, &act, nil); + + /* + * For the correct functioning of devcmd in the + * face of exiting slaves + */ + signal(SIGPIPE, SIG_IGN); + if(signal(SIGTERM, SIG_IGN) != SIG_IGN) + signal(SIGTERM, cleanexit); + if(signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, cleanexit); + + if(sflag == 0) { + act.sa_flags = SA_SIGINFO; + act.sa_sigaction = trapILL; + sigaction(SIGILL, &act, nil); + act.sa_sigaction = trapFPE; + sigaction(SIGFPE, &act, nil); + act.sa_sigaction = trapmemref; + sigaction(SIGBUS, &act, nil); + sigaction(SIGSEGV, &act, nil); + act.sa_flags &= ~SA_SIGINFO; + } + + p = newproc(); + kprocinit(p); + + pw = getpwuid(getuid()); + if(pw != nil) + kstrdup(&eve, pw->pw_name); + else + print("cannot getpwuid\n"); + + p->env->uid = getuid(); + p->env->gid = getgid(); + + emuinit(imod); +} + +int +readkbd(void) +{ + int n; + char buf[1]; + + n = read(0, buf, sizeof(buf)); + if(n < 0) + print("keyboard close (n=%d, %s)\n", n, strerror(errno)); + if(n <= 0) + pexit("keyboard thread", 0); + + switch(buf[0]) { + case '\r': + buf[0] = '\n'; + break; + case DELETE: + buf[0] = 'H' - '@'; + break; + case CTRLC: + cleanexit(0); + break; + } + return buf[0]; +} + +/* + * 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; + nanosleep(&time, NULL); + return 0; +} + +int +limbosleep(ulong milsec) +{ + return osmillisleep(milsec); +} diff --git a/emu/Linux/segflush-386.c b/emu/Linux/segflush-386.c new file mode 100644 index 0000000..18c940d --- /dev/null +++ b/emu/Linux/segflush-386.c @@ -0,0 +1,11 @@ +#include <sys/types.h> +#include <sys/syscall.h> + +#include "dat.h" + +int +segflush(void *a, ulong n) +{ + USED(a); USED(n); + return 0; +} diff --git a/emu/Linux/segflush-arm.c b/emu/Linux/segflush-arm.c new file mode 100644 index 0000000..0392977 --- /dev/null +++ b/emu/Linux/segflush-arm.c @@ -0,0 +1,14 @@ +#include <sys/types.h> +#include <sys/syscall.h> + +#include "dat.h" + +#define SYS_cacheflush __ARM_NR_cacheflush + +int +segflush(void *a, ulong n) +{ + if(n) + syscall(SYS_cacheflush, a, (char*)a+n-1, 1); + return 0; +} diff --git a/emu/Linux/segflush-mips.S b/emu/Linux/segflush-mips.S new file mode 100644 index 0000000..458172f --- /dev/null +++ b/emu/Linux/segflush-mips.S @@ -0,0 +1,16 @@ +#include "syscall.h" +#include <sys/asm.h> +#include <sys/regdef.h> +#include <asm/cachectl.h> + +/* + * int segflush(void *p, ulong len) + */ + +LEAF(segflush) + li a2,BCACHE + li v0,SYS_cacheflush + syscall + li v0,0 + j $31 + END(segflush) diff --git a/emu/Linux/segflush-power.c b/emu/Linux/segflush-power.c new file mode 100644 index 0000000..0804d68 --- /dev/null +++ b/emu/Linux/segflush-power.c @@ -0,0 +1,34 @@ +#include <sys/types.h> +#include <sys/syscall.h> + +#include "dat.h" + + +/* + * from geoff collyer's port + * invalidate instruction cache and write back data cache from a to a+n-1, + * at least. + */ +int +segflush(void *a, ulong n) +{ + ulong *p; + + // cache blocks are often eight words (32 bytes) long, sometimes 16 bytes. + // need to determine it dynamically? + for (p = (ulong *)((ulong)a & ~7UL); (char *)p < (char *)a + n; p++) + __asm__("dcbst 0,%0\n\t" // not dcbf, which writes back, then invalidates + "icbi 0,%0\n\t" + : // no output + : "ar" (p) + ); + __asm__("sync\n\t" + : // no output + : + ); + __asm__("isync\n\t" + : // no output + : + ); + return 0; +} diff --git a/emu/Linux/segflush-spim.S b/emu/Linux/segflush-spim.S new file mode 100644 index 0000000..458172f --- /dev/null +++ b/emu/Linux/segflush-spim.S @@ -0,0 +1,16 @@ +#include "syscall.h" +#include <sys/asm.h> +#include <sys/regdef.h> +#include <asm/cachectl.h> + +/* + * int segflush(void *p, ulong len) + */ + +LEAF(segflush) + li a2,BCACHE + li v0,SYS_cacheflush + syscall + li v0,0 + j $31 + END(segflush) |
