diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /os/js | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'os/js')
| -rw-r--r-- | os/js/README | 10 | ||||
| -rw-r--r-- | os/js/audio.h | 9 | ||||
| -rw-r--r-- | os/js/clock.c | 104 | ||||
| -rw-r--r-- | os/js/cs4231.h | 20 | ||||
| -rw-r--r-- | os/js/dat.h | 163 | ||||
| -rw-r--r-- | os/js/devcs4231.c | 1186 | ||||
| -rw-r--r-- | os/js/devrtc.c | 413 | ||||
| -rw-r--r-- | os/js/fns.h | 110 | ||||
| -rw-r--r-- | os/js/fsv.c | 198 | ||||
| -rw-r--r-- | os/js/io.h | 224 | ||||
| -rw-r--r-- | os/js/iob.c | 13 | ||||
| -rw-r--r-- | os/js/js | 104 | ||||
| -rw-r--r-- | os/js/kbd.c | 482 | ||||
| -rw-r--r-- | os/js/l.s | 560 | ||||
| -rw-r--r-- | os/js/main.c | 564 | ||||
| -rw-r--r-- | os/js/mem.h | 149 | ||||
| -rw-r--r-- | os/js/mkfile | 77 | ||||
| -rw-r--r-- | os/js/mmu.c | 252 | ||||
| -rw-r--r-- | os/js/ns16552.h | 81 | ||||
| -rw-r--r-- | os/js/rom.c | 103 | ||||
| -rw-r--r-- | os/js/rom.h | 57 | ||||
| -rw-r--r-- | os/js/screen.c | 483 | ||||
| -rw-r--r-- | os/js/screen.h | 49 | ||||
| -rw-r--r-- | os/js/softcursor.h | 13 | ||||
| -rw-r--r-- | os/js/superio.c | 216 | ||||
| -rw-r--r-- | os/js/trap.c | 472 | ||||
| -rw-r--r-- | os/js/ureg.h | 45 |
27 files changed, 6157 insertions, 0 deletions
diff --git a/os/js/README b/os/js/README new file mode 100644 index 00000000..1bef576f --- /dev/null +++ b/os/js/README @@ -0,0 +1,10 @@ +This port was done in a matter of days by Tad Hunt, Eric van Hensbergen +and others when they were in the Lucent Inferno Business Unit, with a little +bit of advice from Vita Nuova about various Sparc details (since one +of us had done ports to micro-Sparcs). It is included mainly to +allow another micro-Sparc port to be developed. Javastation-1s +can still be found (but we haven't got one). A good cheap reference +board would be good to have. + +The Javastation running Java and JavaOS was sluggish; running Limbo +under Inferno it was actually quite snappy! diff --git a/os/js/audio.h b/os/js/audio.h new file mode 100644 index 00000000..1d88aa1b --- /dev/null +++ b/os/js/audio.h @@ -0,0 +1,9 @@ +enum +{ + Bufsize = 16*1024, /* 92 ms each */ + Nbuf = 16, /* 1.5 seconds total */ + Rdma = 666, /* XXX - Tad: fixme */ + Wdma = 666, /* XXX - Tad: fixme */ +}; + +#define UNCACHED(type, v) (type*)((ulong)(v)) diff --git a/os/js/clock.c b/os/js/clock.c new file mode 100644 index 00000000..581ee441 --- /dev/null +++ b/os/js/clock.c @@ -0,0 +1,104 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "ureg.h" + +typedef struct Clock0link Clock0link; +typedef struct Clock0link { + void (*clock)(void); + Clock0link* link; +} Clock0link; + +static Clock0link *clock0link; +static Lock clock0lock; + +void +microdelay(int ms) +{ + int i; + + ms *= 13334; /* experimentally indetermined */ + for(i=0; i<ms; i++) + ; +} + +typedef struct Ctr Ctr; +struct Ctr +{ + ulong lim; + ulong ctr; + ulong limnr; /* non-resetting */ + ulong ctl; +}; +Ctr *ctr; + +void +clockinit(void) +{ + KMap *k; + + putphys(TIMECONFIG, 0); /* it's a processor counter */ + k = kmappa(CLOCK, PTENOCACHE|PTEIO); + ctr = (Ctr*)VA(k); + ctr->lim = (CLOCKFREQ/HZ)<<10; +} + +void +clock(Ureg *ur) +{ + Clock0link *lp; + ulong i; + + USED(ur); + + i = ctr->lim; /* clear interrupt */ + USED(i); + /* is this needed? page 6-43 801-3137-10 suggests so */ + ctr->lim = (CLOCKFREQ/HZ)<<10; + + m->ticks++; + + if(up) + up->pc = ur->pc; + + checkalarms(); + + lock(&clock0lock); + for(lp = clock0link; lp; lp = lp->link) + lp->clock(); + unlock(&clock0lock); + + if(up && up->state == Running) { + if(anyready()) + sched(); + } +} + +Timer* +addclock0link(void (*clockfunc)(void), int) +{ + Clock0link *lp; + + if((lp = malloc(sizeof(Clock0link))) == 0){ + print("addclock0link: too many links\n"); + return nil; + } + ilock(&clock0lock); + lp->clock = clockfunc; + lp->link = clock0link; + clock0link = lp; + iunlock(&clock0lock); + return nil; +} + +uvlong +fastticks(uvlong *hz) +{ + if(hz) + *hz = HZ; + return m->ticks; +} diff --git a/os/js/cs4231.h b/os/js/cs4231.h new file mode 100644 index 00000000..daeda1b8 --- /dev/null +++ b/os/js/cs4231.h @@ -0,0 +1,20 @@ +#define IN(x) inb(csdev.port+(x)) +#define OUT(x,v) outb(csdev.port+(x),(v)) + +void +cs4231install(void) +{ + KMap *k; + static int installed=0; + + if(installed) + return; + + k = kmappa(AUDIO_PHYS_PAGE, PTEIO|PTENOCACHE); + + csdev.port = VA(k)+AUDIO_INDEX_OFFSET; + dmasize(Wdma, 8); + dmasize(Rdma, 8); + + installed=1; +} diff --git a/os/js/dat.h b/os/js/dat.h new file mode 100644 index 00000000..e1691f4e --- /dev/null +++ b/os/js/dat.h @@ -0,0 +1,163 @@ +typedef struct Conf Conf; +typedef struct FPenv FPenv; +typedef struct FPU FPU; +typedef struct Label Label; +typedef struct Lock Lock; +typedef struct Mach Mach; +typedef struct Ureg Ureg; +typedef struct Lance Lance; +typedef struct Lancemem Lancemem; +typedef struct Etherpkt Etherpkt; +typedef struct Lancepkt Lancepkt; + +typedef ulong Instr; + +struct Conf +{ + int nmach; /* processors */ + int nproc; /* processes */ + ulong monitor; /* graphics monitor id; 0 for none */ + char ss2; /* is a sparcstation 2 */ + char ss2cachebug; /* has sparcstation2 cache bug */ + int ncontext; /* in mmu */ + int vacsize; /* size of virtual address cache, in bytes */ + int vaclinesize; /* size of cache line */ + ulong npage0; /* total physical pages of memory, bank 0 */ + ulong npage1; /* total physical pages of memory, bank 1 */ + ulong base0; /* base of bank 0 */ + ulong base1; /* base of bank 1 */ + ulong ialloc; /* max interrupt time allocation in bytes */ + ulong npage; /* total physical pages of memory */ + int copymode; /* 0 is copy on write, 1 is copy on reference */ + ulong ipif; /* Ip protocol interfaces */ + ulong ip; /* Ip conversations per interface */ + ulong arp; /* Arp table size */ + ulong frag; /* Ip fragment assemble queue size */ +}; + + +/* + * FPenv.status + */ +enum +{ + FPINIT, + FPACTIVE, + FPINACTIVE, +}; + +struct FPenv +{ + ulong status; + ulong pad; +}; + +/* + * This structure must agree with fpsave and fprestore asm routines + */ +struct FPU +{ + + double regs[17]; /* floating point registers */ + FPenv env; +}; + +/* + * machine dependent definitions used by ../port/dat.h + */ + +struct Label +{ + ulong sp; + ulong pc; +}; + +struct Lock +{ + ulong key; + ulong pc; + ulong sr; + int pri; +}; + +#include "../port/portdat.h" + +/* + * machine dependent definitions not used by ../port/dat.h + */ + +struct Mach +{ + ulong ticks; /* of the clock since boot time */ + int machno; /* physical id of this processor */ + Proc *proc; /* current process on this processor */ + Label sched; /* scheduler wakeup */ + Lock alarmlock; /* access to alarm list */ + void *alarm; /* alarms bound to this clock */ + ulong *contexts; /* hardware context table */ + ulong *ctx; /* the context */ + int fptrap; /* FP trap occurred while unsave */ + + int nrdy; + + int stack[1]; +}; + +/* + * XXX - Eric: It just works.... + */ + +/* + * LANCE CSR3 (bus control bits) + */ +#define BSWP 0x4 +#define ACON 0x2 +#define BCON 0x1 + +struct Lancepkt +{ + uchar d[6]; + uchar s[6]; + uchar type[2]; + uchar data[1500]; + uchar crc[4]; +}; + +/* + * system dependent lance stuff + * filled by lancesetup() + */ +struct Lance +{ + ushort lognrrb; /* log2 number of receive ring buffers */ + ushort logntrb; /* log2 number of xmit ring buffers */ + ushort nrrb; /* number of receive ring buffers */ + ushort ntrb; /* number of xmit ring buffers */ + ushort *rap; /* lance address register */ + ushort *rdp; /* lance data register */ + ushort busctl; /* bus control bits */ + uchar ea[6]; /* our ether addr */ + int sep; /* separation between shorts in lance ram + as seen by host */ + ushort *lanceram; /* start of lance ram as seen by host */ + Lancemem *lm; /* start of lance ram as seen by lance */ + Lancepkt *rp; /* receive buffers (host address) */ + Lancepkt *tp; /* transmit buffers (host address) */ + Lancepkt *lrp; /* receive buffers (lance address) */ + Lancepkt *ltp; /* transmit buffers (lance address) */ +}; + +/* + * Fake kmap + */ +typedef void KMap; +#define VA(k) ((ulong)(k)) +#define kmap(p) (KMap*)((p)->pa|KZERO) +#define kunmap(k) +#define MACHP(n) (n==0? &mach0 : *(Mach**)0) + +extern Mach *m; +extern Proc *up; +extern Mach mach0; + +#define swcursor 1 diff --git a/os/js/devcs4231.c b/os/js/devcs4231.c new file mode 100644 index 00000000..2e02c462 --- /dev/null +++ b/os/js/devcs4231.c @@ -0,0 +1,1186 @@ +/* + * preliminary Crystal CS4231 audio driver, + * initially based on SB16 driver, and therefore needs work. + * for instance, i suspect the linked-list buffering is excessive: + * a rolling buffering scheme or double buffering should be fine, + * and possibly simpler. + * + * To do: + * stop/start? + * is the linux mix_cvt ideal? + * ad1845 differences + * adpcm freezing + */ + +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "devtab.h" +#include "io.h" +#include "audio.h" + +#define DPRINT if(chatty)print + +typedef struct AChan AChan; +typedef struct AQueue AQueue; +typedef struct Buf Buf; +typedef struct Vol Vol; + +enum +{ + Qdir = 0, + Qaudio, + Qaudioctl, + + Fmono = 1, + Fin = 2, + Fout = 4, + + Vaudio = 0, + Vaux1, + Vaux2, + Vline, + Vmic, + Vmono, + Vspeed, + Vchans, + Vbits, + Nvol, + + Speed = 22050, + Ncmd = 50, /* max volume command words */ +}; + +enum { + Paddr= 0, + TRD= 1<<5, + MCE= 1<<6, + Pdata= 1, + Pstatus= 2, + Pio= 3, + + LeftADC= 0, + MGE= 1<<5, + ISline= 0<<6, + ISaux1= 1<<6, + ISmic= 2<<6, + ISloop= 3<<6, + ISmask= 3<<6, + RightADC= 1, + LeftAux1= 2, + Mute= 1<<7, + RightAux1= 3, + LeftAux2= 4, + RightAux2= 5, + LeftDAC= 6, + RightDAC= 7, + OutFormat= 8, + Stereo= 1<<4, + Linear8= 0<<5, + uLaw= 1<<5, + Linear16= 2<<5, + aLaw= 3<<5, + ADPCM= 5<<5, + Fmask= 7<<5, + Config= 9, + PEN= 1<<0, + CEN= 1<<1, + Nocal= 0<<3, + Convcal= 1<<3, + DACcal= 2<<3, + Fullcal= 3<<3, + PinControl= 10, + IEN= 1<<1, + DEN= 1<<3, + Xctl0= 1<<6, + Xctl1= 1<<7, + Status= 11, + ACI= 1<<5, + Mode= 12, + Mode2= 1<<6, + Loopback= 13, + LBE= 1<<0, + PlayCount1= 14, + PlayCount0= 15, + Feature1= 16, + PMCE= 1<<4, + CMCE= 1<<5, + Feature2= 17, + LeftLine= 18, + RightLine= 19, + Timer0= 20, + Timer1= 21, + Feature3= 23, + FeatureStatus= 24, + PI= 1<<4, /* playback interrupt */ + CI= 1<<5, /* capture interrupt */ + TI= 1<<6, /* timer interrupt */ + ChipID= 25, + MonoCtl= 26, + MBY= 1<<5, /* mono bypass */ + MOM= 1<<6, + InFormat= 28, + RecCount1= 30, + RecCount0= 31, +}; + +#define csdelay() microdelay(1) + +static Dirtab audiodir[] = +{ + "audio", {Qaudio}, 0, 0666, + "audioctl", {Qaudioctl}, 0, 0666, +}; +#define NPORT (sizeof audiodir/sizeof(Dirtab)) + +struct Buf +{ + uchar* virt; + int count; + Buf* next; +}; +struct AQueue +{ + Lock; + Buf* first; + Buf* last; +}; +struct AChan +{ + QLock; + Rendez r; + Buf buf[Nbuf]; /* buffers and queues */ + AQueue empty; + AQueue full; + Buf* current; + Buf* filling; + int flushing; +}; +static struct +{ + QLock; + int opened; + int bufinit; /* boolean if buffers allocated */ + int rivol[Nvol]; /* right/left input/output volumes */ + int livol[Nvol]; + int rovol[Nvol]; + int lovol[Nvol]; + int loopback; + + AChan in; + AChan out; +} audio; + +static char* encname(int); + +static int dacload(int, int); +static int auxload(int, int); +static int adcload(int, int); +static int monoload(int, int); + +struct Vol +{ + char* name; + int flag; + int ilval; /* initial values */ + int irval; + int reg; + int (*load)(int, int); +}; + +static Vol volumes[] = { +[Vaudio] {"audio", Fout, 50, 50, LeftDAC, dacload}, +[Vaux1] {"aux1", Fin, 0, 0, LeftAux1, auxload}, +[Vaux2] {"aux2", Fin, 0, 0, LeftAux2, auxload}, +[Vline] {"line", Fin, 0, 0, LeftLine, auxload}, +[Vmono] {"mono", Fin|Fout|Fmono, 0, 0, MonoCtl, monoload}, +[Vmic] {"mic", Fin, 0, 0, LeftADC, adcload}, + +[Vspeed] {"rate", Fin|Fout|Fmono, Speed, Speed,}, +[Vchans] {"chans", Fin|Fout|Fmono, 2, 2,}, +[Vbits] {"bits", Fin|Fout|Fmono, 8, 8,}, + {0}, +}; + +static struct +{ + Lock; + int port; + int irq; + uchar sticky; + uchar regs[32]; +} csdev; + +static void contininput(void); +static void continoutput(void); + +static char Evolume[] = "illegal audioctl specifier"; + +static int chatty; + +#include "cs4231.h" + +static int +xin(int r) +{ + int i; + + for(i=100; --i >= 0 && IN(Paddr) & 0x80;) + csdelay(); + OUT(Paddr, r|csdev.sticky); + csdelay(); + return IN(Pdata); +} + +static void +xout(int r, int v) +{ + int i; + + for(i=100; --i >= 0 && IN(Paddr) & 0x80;) + csdelay(); + OUT(Paddr, r|csdev.sticky); + csdelay(); + OUT(Pdata, v); + //csdelay(); +} + +static void +speaker(int on) +{ + int s; + + s = xin(PinControl); + if(on) + s |= Xctl0; + else + s &= ~Xctl0; + xout(PinControl, s); +} + +static Buf* +getbuf(AQueue *q) +{ + Buf *b; + + ilock(q); + b = q->first; + if(b) + q->first = b->next; + iunlock(q); + + return b; +} + +static void +putbuf(AQueue *q, Buf *b) +{ + ilock(q); + b->next = 0; + if(q->first) + q->last->next = b; + else + q->first = b; + q->last = b; + iunlock(q); +} + +static void +achanreset(AChan *ac) +{ + int i; + + ac->filling = 0; + ac->flushing = 0; + ac->current = 0; + ac->empty.first = 0; + ac->empty.last = 0; + ac->full.first = 0; + ac->full.last = 0; + for(i=0; i<Nbuf; i++){ + ac->buf[i].count = 0; + putbuf(&ac->empty, &ac->buf[i]); + } +} + +static void +startoutput(void) +{ + ilock(&csdev); + if(audio.out.current == 0) + continoutput(); + iunlock(&csdev); +} + +static void +continoutput(void) +{ + Buf *b; + int f; + ulong n; + + b = getbuf(&audio.out.full); + audio.out.current = b; + //xout(Config, xin(Config)&~PEN); + if(b){ + n = b->count; + dmasetup(Wdma, b->virt, n, 0); + f = xin(OutFormat); + if((f & Fmask) == ADPCM) + n >>= 2; + else{ + if((f & Fmask) == Linear16) + n >>= 1; + if(f & Stereo) + n >>= 1; + } + n--; + xout(PlayCount0, n); + xout(PlayCount1, n>>8); + xout(Config, xin(Config)|PEN); + DPRINT("cs: out %d\n", n); + } else + xout(Config, xin(Config)&~PEN); +} + +static void +startinput(void) +{ + ilock(&csdev); + if(audio.in.current == 0) + contininput(); + iunlock(&csdev); +} + +static void +contininput(void) +{ + Buf *b; + int f; + ulong n; + + xout(Config, xin(Config)&~CEN); + if(!audio.opened || audio.in.flushing){ + return; + } + b = getbuf(&audio.in.empty); + audio.in.current = b; + if(b){ + n = Bufsize; + dmasetup(Rdma, b->virt, Bufsize, 1); + f = xin(InFormat); + if((f & Fmask) == ADPCM) + n >>= 2; + else{ + if((f & Fmask) == Linear16) + n >>= 1; + if(f & Stereo) + n >>= 1; + } + n--; + xout(RecCount0, n); + xout(RecCount1, n>>8); + xout(Config, xin(Config)|CEN); + DPRINT("cs: in %d\n", n); + } +} + +static void +cswait(void) +{ + int i; + + for(i=50; --i >= 0 && IN(Paddr) & 0x80;) + microdelay(2000); + if(i < 0) + print("cswait1\n"); + for(i=1000; --i >= 0 && (xin(Status) & ACI) == 0;) + csdelay(); + for(i=1000; --i >= 0 && xin(Status) & ACI;) + microdelay(2000); + /* could give error(Eio) if i < 0 */ + if(i < 0) + print("cswait2\n"); +} + +static int +csspeed(int freq) +{ + int i; + static int freqtab[] = { /* p. 33 CFS2-CFS0 */ + /* xtal1 xtal2 */ + 8000, 5510, + 16000, 11025, + 27420, 18900, + 32000, 22050, + 0, 37800, + 0, 44100, + 48000, 33075, + 9600, 6620, + }; + for(i=0; i<16; i++) + if(freqtab[i] == freq){ + xout(OutFormat, (xin(OutFormat)&~0xF) | i); + return 1; + } + return 0; +} + +static void +csformat(int r, int flag, int form, int *vec) +{ + int v; + + if(form == Linear8){ + if(vec[Vbits] == 16) + form = Linear16; + else if(vec[Vbits] == 4) + form = ADPCM; + } + if(vec[Vchans] == 2) + form |= Stereo; + DPRINT("csformat(%x,%x,%x)\n", r, flag, form); + if((xin(r)&0xF0) != form){ + v = xin(Feature1); + xout(Feature1, v|flag); + xout(r, (xin(r)&~0xF0)|form); + xout(Feature1, v); + } + csdev.regs[r] = form; +} + +static void +cs4231intr(Ureg*, void*) +{ + int ir, s; + Buf *b; + + lock(&csdev); + csdev.sticky |= TRD; + ir = IN(Pstatus); + s = xin(FeatureStatus); + if(s & PI){ + b = audio.out.current; + audio.out.current = 0; + dmaend(Wdma); + continoutput(); + if(b) + putbuf(&audio.out.empty, b); + wakeup(&audio.out.r); + } + if(s & CI){ + b = audio.in.current; + audio.in.current = 0; + dmaend(Rdma); + contininput(); + if(b){ + b->count = Bufsize; + putbuf(&audio.in.full, b); + } + wakeup(&audio.in.r); + } + OUT(Pstatus, 0); + csdev.sticky &= ~TRD; + unlock(&csdev); + if(s & 0xF) + DPRINT("audiointr: #%x\n", s); +} + +static int +anybuf(void *p) +{ + return ((AChan*)p)->empty.first != 0; +} + +static int +anyinput(void *p) +{ + return ((AChan*)p)->full.first != 0; +} + +static int +outcomplete(void *p) +{ + return ((AChan*)p)->full.first == 0 && ((AChan*)p)->current==0; +} + +static int +incomplete(void *p) +{ + return ((AChan*)p)->current == 0; +} + +static void +acbufinit(AChan *ac) +{ + int i; + void *p; + + for(i=0; i<Nbuf; i++) { + //p = xspanalloc(Bufsize, CACHELINESZ, 64*1024); + //dcflush(p, Bufsize); + p = xalloc(Bufsize); + ac->buf[i].virt = UNCACHED(uchar, p); + } +} + +static void +setempty(void) +{ + ilock(&csdev); + achanreset(&audio.in); + achanreset(&audio.out); + iunlock(&csdev); +} + +void +cs4231reset(void) +{ +} + +static char mix_cvt[101] = { + 0, 0,3,7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42, + 43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65, + 65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79, + 80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90, + 91,91,92,92,93,93,94,94,95,95,96,96,96,97,97,98,98,98,99,99, + 100 +}; + +static int +dacload(int r, int v) +{ + USED(r); + DPRINT("dacload(%x,%d)\n", r, v); + if(v == 0) + return Mute; + return 63-((v*63)/100); +} + +static int +monoload(int r, int v) +{ + DPRINT("monoload(%x,%d)\n", r, v); + if(v == 0) + return r|Mute; + return (r&~(Mute|MBY))|(15-((v*15)/100)); +} + +static int +auxload(int r, int v) +{ + DPRINT("auxload(%x,%d)\n", r, v); + USED(r); + if(v == 0) + return Mute; + return 31-(v*31)/100; +} + +static int +adcload(int r, int v) +{ + DPRINT("adcload(%x,%d)\n", r, v); + return (r&~0xF)|((v*15)/100)|MGE; +} + +static void +mxvolume(void) +{ + Vol *v; + int i, l, r; + + ilock(&csdev); + speaker(0); + for(i =0; volumes[i].name; i++){ + v = &volumes[i]; + if(v->load == 0) + continue; + if(v->flag & Fin){ + l = audio.livol[i]; + r = audio.rivol[i]; + } else { + l = audio.lovol[i]; + r = audio.rovol[i]; + } + if(l < 0) + l = 0; + if(r < 0) + r = 0; + if(l > 100) + l = 100; + if(r > 100) + r = 100; + l = mix_cvt[l]; + r = mix_cvt[r]; + if((v->flag & Fmono) == 0){ + xout(v->reg, (*v->load)(xin(v->reg), l)); + xout(v->reg+1, (*v->load)(xin(v->reg+1), r)); + } else + xout(v->reg, (*v->load)(xin(v->reg), l)); + } + xout(LeftADC, (xin(LeftADC)&~ISmask)|csdev.regs[LeftADC]); + xout(RightADC, (xin(RightADC)&~ISmask)|csdev.regs[RightADC]); + if(audio.loopback) + xout(Loopback, xin(Loopback)|LBE); + else + xout(Loopback, xin(Loopback)&~LBE); + csformat(InFormat, CMCE, csdev.regs[InFormat], audio.livol); + csformat(OutFormat, PMCE, csdev.regs[OutFormat], audio.lovol); + if(audio.lovol[Vaudio] || audio.rovol[Vaudio]) + speaker(1); + iunlock(&csdev); +} + +static void +flushinput(void) +{ + Buf *b; + + ilock(&csdev); + audio.in.flushing = 1; + iunlock(&csdev); + qlock(&audio.in); + if(waserror()){ + qunlock(&audio.in); + nexterror(); + } + sleep(&audio.in.r, incomplete, &audio.in); + qunlock(&audio.in); + poperror(); + ilock(&csdev); + audio.in.flushing = 0; + iunlock(&csdev); + if((b = audio.in.filling) != 0){ + audio.in.filling = 0; + putbuf(&audio.in.empty, b); + } + while((b = getbuf(&audio.in.full)) != 0) + putbuf(&audio.in.empty, b); +} + +static void +waitoutput(void) +{ + qlock(&audio.out); + if(waserror()){ + qunlock(&audio.out); + nexterror(); + } + startoutput(); + while(!outcomplete(&audio.out)) + sleep(&audio.out.r, outcomplete, &audio.out); + qunlock(&audio.out); + poperror(); +} + +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; + } +} + +void +cs4231init(void) +{ + cs4231install(); + + csdev.regs[LeftADC] = ISmic; + csdev.regs[RightADC] = ISmic; + dmasize(Wdma, 8); + dmasize(Rdma, 8); + csdev.sticky = 0; + OUT(Paddr, Mode); + csdelay(); + if((IN(Pdata) & 0x8F) != 0x8a){ + DPRINT("port %x not cs4231a: %x\n", IN(Pdata)); + return; + } + print("audio0: cs4231a: port %x irq %d wdma %d rdma %d\n", csdev.port, csdev.irq, Wdma, Rdma); + + resetlevel(); + + cswait(); + OUT(Paddr, Mode); + csdelay(); + OUT(Pdata, Mode2|IN(Pdata)); /* mode2 for all the trimmings */ + csdelay(); + cswait(); + + csdev.sticky = MCE; + xout(Config, Fullcal); + csspeed(volumes[Vspeed].ilval); + csformat(InFormat, CMCE, Linear8, audio.livol); + csformat(OutFormat, PMCE, Linear8, audio.lovol); + csdev.sticky &= ~MCE; + OUT(Paddr, csdev.sticky); + microdelay(10000); + cswait(); /* recalibration takes ages */ + + xout(FeatureStatus, 0); + OUT(Pstatus, 0); + setvec(csdev.irq, cs4231intr, 0); + xout(PinControl, xin(PinControl)|IEN); +} + +Chan* +cs4231attach(char *param) +{ + return devattach('A', param); +} + +Chan* +cs4231clone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +cs4231walk(Chan *c, char *name) +{ + return devwalk(c, name, audiodir, NPORT, devgen); +} + +void +cs4231stat(Chan *c, char *db) +{ + devstat(c, db, audiodir, NPORT, devgen); +} + +Chan* +cs4231open(Chan *c, int omode) +{ + switch(c->qid.path & ~CHDIR) { + default: + error(Eperm); + break; + + case Qaudioctl: + case Qdir: + break; + + case Qaudio: + qlock(&audio); + if(audio.opened){ + qunlock(&audio); + error(Einuse); + } + if(audio.bufinit == 0) { + audio.bufinit = 1; + acbufinit(&audio.in); + acbufinit(&audio.out); + } + audio.opened = 1; + setempty(); + qunlock(&audio); + mxvolume(); + break; + } + c = devopen(c, omode, audiodir, NPORT, devgen); + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + + return c; +} + +void +cs4231create(Chan *c, char *name, int omode, ulong perm) +{ + USED(c, name, omode, perm); + error(Eperm); +} + +void +cs4231close(Chan *c) +{ + Buf *b; + + switch(c->qid.path & ~CHDIR) { + default: + error(Eperm); + break; + + case Qdir: + case Qaudioctl: + break; + + case Qaudio: + if(c->flag & COPEN) { + qlock(&audio); + audio.opened = 0; + if(waserror()){ + qunlock(&audio); + nexterror(); + } + b = audio.out.filling; + if(b){ + audio.out.filling = 0; + putbuf(&audio.out.full, b); + } + waitoutput(); + flushinput(); + //tsleep(&up->sleep, return0, 0, 500); + //speaker(0); + qunlock(&audio); + poperror(); + } + break; + } +} + +long +cs4231read(Chan *c, char *a, long n, vlong offset) +{ + int liv, riv, lov, rov, ifmt, ofmt; + long m, n0; + char buf[350]; + Buf *b; + int j; + + n0 = n; + switch(c->qid.path & ~CHDIR) { + default: + error(Eperm); + break; + + case Qdir: + return devdirread(c, a, n, audiodir, NPORT, devgen); + + case Qaudio: + qlock(&audio.in); + if(waserror()){ + qunlock(&audio.in); + nexterror(); + } + while(n > 0) { + b = audio.in.filling; + if(b == 0) { + b = getbuf(&audio.in.full); + if(b == 0) { + startinput(); + sleep(&audio.in.r, anyinput, &audio.in); + continue; + } + audio.in.filling = b; + b->count = 0; + } + m = Bufsize-b->count; + if(m > n) + m = n; + memmove(a, b->virt+b->count, m); + + b->count += m; + n -= m; + a += m; + if(b->count >= Bufsize) { + audio.in.filling = 0; + putbuf(&audio.in.empty, b); + } + } + qunlock(&audio.in); + poperror(); + break; + + case Qaudioctl: + j = 0; + buf[0] = 0; + for(m=0; volumes[m].name; m++){ + 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((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"); + } + ifmt = xin(InFormat); + ofmt = xin(OutFormat); + if(ifmt != ofmt){ + j += snprint(buf+j, sizeof(buf)-j, "in enc %s\n", encname(ifmt)); + j += snprint(buf+j, sizeof(buf)-j, "out enc %s\n", encname(ofmt)); + } else + j += snprint(buf+j, sizeof(buf)-j, "enc %s\n", encname(ifmt)); + j += snprint(buf+j, sizeof(buf)-j, "loop %d\n", audio.loopback); + {int i; for(i=0; i<32; i++){j += snprint(buf+j, sizeof(buf)-j, " %d:%x", i, xin(i)); }j += snprint(buf+j,sizeof(buf)-j,"\n");} + USED(j); + + return readstr(offset, a, n, buf); + } + return n0-n; +} + +Block* +cs4231bread(Chan *c, long n, ulong offset) +{ + return devbread(c, n, offset); +} + +long +cs4231write(Chan *c, char *a, long n, vlong offset) +{ + long m, n0; + int i, nf, v, left, right, in, out, fmt, doload; + char buf[255], *field[Ncmd]; + Buf *b; + + USED(offset); + + n0 = n; + switch(c->qid.path & ~CHDIR) { + default: + error(Eperm); + break; + + case Qaudioctl: + waitoutput(); + flushinput(); + qlock(&audio); + if(waserror()){ + qunlock(&audio); + nexterror(); + } + v = Vaudio; + doload = 0; + left = 1; + right = 1; + in = 1; + out = 1; + if(n > sizeof(buf)-1) + n = sizeof(buf)-1; + memmove(buf, a, 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], 0, 10); + 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; + if(v == Vspeed){ + ilock(&csdev); + csdev.sticky = MCE; + csspeed(m); + csdev.sticky &= ~MCE; + OUT(Paddr, csdev.sticky); + microdelay(10000); + cswait(); + iunlock(&csdev); + } else + doload = 1; + continue; + } + + 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; + break; + } + } + if(volumes[m].name) + continue; + + if(strcmp(field[i], "chat") == 0){ + chatty = !chatty; + continue; + } + + if(strcmp(field[i], "reset") == 0) { + resetlevel(); + doload = 1; + continue; + } + if(strcmp(field[i], "loop") == 0) { + if(++i >= nf) + error(Evolume); + audio.loopback = strtoul(field[i], 0, 10); + doload = 1; + continue; + } + if(strcmp(field[i], "enc") == 0) { + if(++i >= nf) + error(Evolume); + fmt = -1; + if(strcmp(field[i], "ulaw") == 0) + fmt = uLaw; + else if(strcmp(field[i], "alaw") == 0) + fmt = aLaw; + else if(strcmp(field[i], "pcm") == 0) + fmt = Linear8; + else if(strcmp(field[i], "adpcm") == 0) + fmt = ADPCM; + else + error(Evolume); + if(in) + csdev.regs[InFormat] = fmt; + if(out) + csdev.regs[OutFormat] = fmt; + doload = 1; + continue; + } + if(strcmp(field[i], "dev") == 0) { + if(++i >= nf) + error(Evolume); + if(in){ + fmt = -1; + if(strcmp(field[i], "mic") == 0) + fmt = ISmic; + else if(strcmp(field[i], "line") == 0) + fmt = ISline; + else if(strcmp(field[i], "aux1") == 0) + fmt = ISaux1; + else if(strcmp(field[i], "loop") == 0) + fmt = ISloop; + else + error(Evolume); + if(left) + csdev.regs[LeftADC] = fmt; + if(right) + csdev.regs[RightADC] = fmt; + doload = 1; + } + continue; + } + if(strcmp(field[i], "in") == 0) { + in = 1; + out = 0; + continue; + } + if(strcmp(field[i], "out") == 0) { + in = 0; + out = 1; + continue; + } + if(strcmp(field[i], "left") == 0) { + left = 1; + right = 0; + continue; + } + if(strcmp(field[i], "right") == 0) { + left = 0; + right = 1; + continue; + } + error(Evolume); + } + if(doload) + mxvolume(); + qunlock(&audio); + poperror(); + n=0; + break; + + case Qaudio: + qlock(&audio.out); + if(waserror()){ + qunlock(&audio.out); + nexterror(); + } + while(n > 0) { + b = audio.out.filling; + if(b == 0) { + b = getbuf(&audio.out.empty); + if(b == 0) { + startoutput(); + sleep(&audio.out.r, anybuf, &audio.out); + continue; + } + b->count = 0; + audio.out.filling = b; + } + + m = Bufsize-b->count; + if(m > n) + m = n; + memmove(b->virt+b->count, a, m); + + b->count += m; + n -= m; + a += m; + if(b->count >= Bufsize) { + audio.out.filling = 0; + putbuf(&audio.out.full, b); + } + } + qunlock(&audio.out); + poperror(); + break; + } + return n0 - n; +} + +long +cs4231bwrite(Chan *c, Block *bp, ulong offset) +{ + return devbwrite(c, bp, offset); +} + +void +cs4231remove(Chan *c) +{ + USED(c); + error(Eperm); +} + +void +cs4231wstat(Chan *c, char *dp) +{ + USED(c, dp); + error(Eperm); +} + +static char * +encname(int v) +{ + switch(v & ~(0xF|Stereo)){ + case uLaw: return "ulaw"; + case aLaw: return "alaw"; + case Linear8: return "pcm"; + case Linear16: return "pcm16"; + case ADPCM: return "adpcm"; + default: return "?"; + } +} diff --git a/os/js/devrtc.c b/os/js/devrtc.c new file mode 100644 index 00000000..25fcfa1e --- /dev/null +++ b/os/js/devrtc.c @@ -0,0 +1,413 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "io.h" + +/* + * Mostek MK48T12-15 Zeropower/Timekeeper + * This driver is actually portable. + */ +typedef struct Rtc Rtc; +struct Rtc +{ + int sec; + int min; + int hour; + int wday; + int mday; + int mon; + int year; +}; + +static uchar rtcgencksum(void); +static void setrtc(Rtc *rtc); +static long rtctime(void); +static int *yrsize(int yr); +static int *yrsize(int yr); +static ulong rtc2sec(Rtc *rtc); +static void sec2rtc(ulong secs, Rtc *rtc); + +static struct +{ + uchar *cksum; + uchar *ram; + RTCdev *rtc; +}nvr; + +enum{ + Qdir, + Qrtc, + Qnvram, +}; + +QLock rtclock; /* mutex on clock operations */ + +static Dirtab rtcdir[]={ + ".", {Qdir, 0, QTDIR}, 0, 0555, + "rtc", {Qrtc, 0}, 0, 0666, + "nvram", {Qnvram, 0}, NVWRITE, 0666, +}; +#define NRTC (sizeof(rtcdir)/sizeof(rtcdir[0])) + +static void +rtcinit(void) +{ + KMap *k; + + k = kmappa(NVR_CKSUM_PHYS, PTENOCACHE|PTEIO); + nvr.cksum = (uchar*)VA(k); + + k = kmappa(NVR_PHYS, PTENOCACHE|PTEIO); + nvr.ram = (uchar*)VA(k); + nvr.rtc = (RTCdev*)(VA(k)+RTCOFF); + + rtcgencksum(); +} + +static Chan* +rtcattach(char *spec) +{ + return devattach('r',spec); +} + +static Walkqid* +rtcwalk(Chan *c, Chan *nc, char **name, int nname) +{ + return devwalk(c, nc, name, nname, rtcdir, NRTC, devgen); +} + +static int +rtcstat(Chan *c, uchar *dp, int n) +{ + return devstat(c, dp, n, rtcdir, NRTC, devgen); +} + +static Chan* +rtcopen(Chan *c, int omode) +{ + omode = openmode(omode); + switch((ulong)c->qid.path){ + case Qrtc: + if(strcmp(up->env->user, eve)!=0 && omode!=OREAD) + error(Eperm); + break; + case Qnvram: + if(strcmp(up->env->user, eve)!=0) + error(Eperm); + } + return devopen(c, omode, rtcdir, NRTC, devgen); +} + +static void +rtccreate(Chan *c, char *name, int omode, ulong perm) +{ + USED(c, name, omode, perm); + error(Eperm); +} + +static void +rtcclose(Chan *c) +{ + USED(c); +} + +static long +rtcread(Chan *c, void *buf, long n, vlong offset) +{ + ulong t, ot; + + if(c->qid.type & QTDIR) + return devdirread(c, buf, n, rtcdir, NRTC, devgen); + + switch((ulong)c->qid.path){ + case Qrtc: + qlock(&rtclock); + t = rtctime(); + do{ + ot = t; + t = rtctime(); /* make sure there's no skew */ + }while(t != ot); + qunlock(&rtclock); + n = readnum(offset, buf, n, t, 12); + return n; + case Qnvram: + if(offset > NVREAD) + return 0; + if(n > NVREAD - offset) + n = NVREAD - offset; + qlock(&rtclock); + memmove(buf, nvr.ram+offset, n); + qunlock(&rtclock); + return n; + } + error(Egreg); + return 0; /* not reached */ +} + +/* + * XXX - Tad: fixme to generate the correct checksum + */ +static uchar +rtcgencksum(void) +{ + uchar cksum; + int i; + static uchar p1cksum = 0; + static uchar p1cksumvalid=0; + + if(!p1cksumvalid) { + for(i=1; i < 0x1000 ; i++) + p1cksum ^= nvr.cksum[i]; + p1cksumvalid = 1; + } + + cksum = p1cksum; + + for(i=0; i < 0xfdf ; i++) { + cksum ^= nvr.ram[i]; + } + + return cksum; +} + +static long +rtcwrite(Chan *c, void *buf, long n, vlong offset) +{ + Rtc rtc; + ulong secs; + char *cp, sbuf[32]; + + switch((ulong)c->qid.path){ + case Qrtc: + /* + * read the time + */ + if(offset != 0 || n >= sizeof(sbuf)-1) + error(Ebadarg); + memmove(sbuf, buf, n); + sbuf[n] = '\0'; + cp = sbuf; + while(*cp){ + if(*cp>='0' && *cp<='9') + break; + cp++; + } + secs = strtoul(cp, 0, 0); + /* + * convert to bcd + */ + sec2rtc(secs, &rtc); + /* + * write it + */ + qlock(&rtclock); + setrtc(&rtc); + qunlock(&rtclock); + return n; + case Qnvram: + if(offset > NVWRITE) + return 0; + if(n > NVWRITE - offset) + n = NVWRITE - offset; + qlock(&rtclock); + memmove(nvr.ram+offset, buf, n); + *nvr.cksum = rtcgencksum(); + qunlock(&rtclock); + return n; + } + error(Egreg); + return 0; /* not reached */ +} + +#define bcd2dec(bcd) (((((bcd)>>4) & 0x0F) * 10) + ((bcd) & 0x0F)) +#define dec2bcd(dec) ((((dec)/10)<<4)|((dec)%10)) + +static void +setrtc(Rtc *rtc) +{ + struct RTCdev *dev; + + dev = nvr.rtc; + dev->control |= RTCWRITE; + wbflush(); + dev->year = dec2bcd(rtc->year % 100); + dev->mon = dec2bcd(rtc->mon); + dev->mday = dec2bcd(rtc->mday); + dev->hour = dec2bcd(rtc->hour); + dev->min = dec2bcd(rtc->min); + dev->sec = dec2bcd(rtc->sec); + wbflush(); + dev->control &= ~RTCWRITE; + wbflush(); +} + +static long +rtctime(void) +{ + struct RTCdev *dev; + Rtc rtc; + + dev = nvr.rtc; + dev->control |= RTCREAD; + wbflush(); + rtc.sec = bcd2dec(dev->sec) & 0x7F; + rtc.min = bcd2dec(dev->min & 0x7F); + rtc.hour = bcd2dec(dev->hour & 0x3F); + rtc.mday = bcd2dec(dev->mday & 0x3F); + rtc.mon = bcd2dec(dev->mon & 0x3F); + rtc.year = bcd2dec(dev->year); + dev->control &= ~RTCREAD; + wbflush(); + + if (rtc.mon < 1 || rtc.mon > 12) + return 0; + /* + * the world starts Jan 1 1970 + */ + if(rtc.year < 70) + rtc.year += 2000; + else + rtc.year += 1900; + + return rtc2sec(&rtc); +} + +#define SEC2MIN 60L +#define SEC2HOUR (60L*SEC2MIN) +#define SEC2DAY (24L*SEC2HOUR) + +/* + * days per month plus days/year + */ +static int dmsize[] = +{ + 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; +static int ldmsize[] = +{ + 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * return the days/month for the given year + */ +static int * +yrsize(int yr) +{ + if((yr % 4) == 0) + return ldmsize; + else + return dmsize; +} + +/* + * compute seconds since Jan 1 1970 + */ +static ulong +rtc2sec(Rtc *rtc) +{ + ulong secs; + int i; + int *d2m; + + secs = 0; + + /* + * seconds per year + */ + for(i = 1970; i < rtc->year; i++){ + d2m = yrsize(i); + secs += d2m[0] * SEC2DAY; + } + + /* + * seconds per month + */ + d2m = yrsize(rtc->year); + for(i = 1; i < rtc->mon; i++) + secs += d2m[i] * SEC2DAY; + + secs += (rtc->mday-1) * SEC2DAY; + secs += rtc->hour * SEC2HOUR; + secs += rtc->min * SEC2MIN; + secs += rtc->sec; + + return secs; +} + +/* + * compute rtc from seconds since Jan 1 1970 + */ +static void +sec2rtc(ulong secs, Rtc *rtc) +{ + int d; + long hms, day; + int *d2m; + + /* + * break initial number into days + */ + hms = secs % SEC2DAY; + day = secs / SEC2DAY; + if(hms < 0) { + hms += SEC2DAY; + day -= 1; + } + + /* + * generate hours:minutes:seconds + */ + rtc->sec = hms % 60; + d = hms / 60; + rtc->min = d % 60; + d /= 60; + rtc->hour = d; + + /* + * year number + */ + if(day >= 0) + for(d = 1970; day >= *yrsize(d); d++) + day -= *yrsize(d); + else + for (d = 1970; day < 0; d--) + day += *yrsize(d-1); + rtc->year = d; + + /* + * generate month + */ + d2m = yrsize(rtc->year); + for(d = 1; day >= d2m[d]; d++) + day -= d2m[d]; + rtc->mday = day + 1; + rtc->mon = d; + + return; +} + +Dev rtcdevtab = { + 'r', + "rtc", + + devreset, + rtcinit, + devshutdown, + rtcattach, + rtcwalk, + rtcstat, + rtcopen, + rtccreate, + rtcclose, + rtcread, + devbread, + rtcwrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/os/js/fns.h b/os/js/fns.h new file mode 100644 index 00000000..2ad8ac14 --- /dev/null +++ b/os/js/fns.h @@ -0,0 +1,110 @@ +#include "../port/portfns.h" +#define dumplongs(x, y, z) +#define clockcheck() +#define setpanic() + +void links(void); +void prom_printf(char *format, ...); /* can't use after mmuinit() */ +void savefpregs(FPU *); +void restfpregs(FPU*); +void savefsr(FPenv *); +void restfsr(FPenv *); +void disabfp(void); +void fpinit(void); +void fpsave(FPU*); +void bootargs(ulong); +void cacheinit(void); +ulong call_openboot(void*, ...); +void clearftt(ulong); +#define clearmmucache() +void clockinit(void); +void clock(Ureg*); +#define coherence() /* nothing to do on uniprocessor */ +void dcflush(void); +void disabfp(void); +void enabfp(void); +char* excname(ulong); + +#define flushpage(pa) icflush() +void flushtlb(void); +void flushtlbctx(void); +void flushtlbpage(ulong); +int fpcr(int); +int fpquiet(void); +void fpregrestore(char*); +void fpregsave(char*); +int fptrap(void); +int getfpq(ulong*); +ulong getfsr(void); +ulong getpcr(void); +ulong getphys(ulong); +ulong getrmmu(ulong); +ulong getpsr(void); +void icflush(void); +int isvalid_va(void*); +void flushicache(void); +void flushdcache(void); +void flushiline(ulong); +void flushdline(ulong); +#define idlehands() /* nothing to do in the runproc */ +void intrinit(void); +void ioinit(void); +void kbdclock(void); +void kbdrepeat(int); +void kbdinit(void); +void kbdintr(void); +#define KADDR(a) ((void*)((ulong)(a)|KZERO)) +#define PADDR(a) ((ulong)(a)&~KZERO) +void kmapinit(void); +void* kmappa(ulong, ulong); +ulong kmapsbus(int); +ulong kmapdma(ulong, ulong); +int kprint(char*, ...); +void kproftimer(ulong); +void kunmap(KMap*); +void lanceintr(void); +void lancesetup(Lance*); +void lancetoggle(void); +void mmuinit(void); +void mousebuttons(int); +void printinit(void); +#define procrestore(p) +#define procsave(p) +#define procsetup(x) ((p)->fpstate = FPinit) +void putphys(ulong, ulong); +void putrmmu(ulong, ulong); +void putstr(char*); +void puttbr(ulong); +void systemreset(void); +void screeninit(void); +void screenputc(char *); +void screenputs(char*, int); +void scsiintr(void); +void setpcr(ulong); +void setpsr(ulong); +void spldone(void); +void trap(Ureg*); +void trapinit(void); +#define wbflush() /* mips compatibility */ +#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1])) +ulong getcallerpc(void*); +void dumpregs(Ureg*); + +void ns16552special(int,int,Queue**,Queue**,int (*)(Queue*,int)); +char ns16552dmarcv(int); +void ns16552install(void); +void ns16552intr(int); + +long dmasetup(int,void*,long,int); +void dmaend(int); +int dmacount(int); + +void superioinit(ulong va, uchar*, uchar*, uchar*, uchar*); +ulong superiova(void); + +uchar superio_readctl(void); +uchar superio_readdata(void); +void superio_writectl(uchar val); +void superio_writedata(uchar val); +void outb(ulong, uchar); +uchar inb(ulong); diff --git a/os/js/fsv.c b/os/js/fsv.c new file mode 100644 index 00000000..9832ce3b --- /dev/null +++ b/os/js/fsv.c @@ -0,0 +1,198 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "io.h" +#include "dat.h" +#include "fns.h" + +#include <draw.h> +#include <memdraw.h> +#include "screen.h" + +extern Video *vid; +extern Memimage gscreen; + +static Vctlr* init(Vctlr* vctlr, int x, int y, int d); +static int setcolour(ulong p, ulong r, ulong g, ulong b); +static void enable(void); +static void disable(void); +static void move(int cx, int cy); +static void load(Cursor *c); +static int isloaded(void); + +extern void* memcpy(void*, void*, int); +extern void cursorupdate0(void); + +Vctlr FSV = { + "FSV", /* name */ + init, /* init */ + 0, /* page */ + setcolour, /* setcolor */ + + enable, /* enable cursor fn */ + disable, /* disable cursor fn */ + move, /* move cursor fn */ + load, /* load cursor fn */ + isloaded, /* is cursor loaded? */ + 0, /* deprecated */ + + 1024, /* screen width (x) */ + 768, /* screen height (y) */ + 3, /* depth */ + + 0, /* hidecount */ + 0, /* loaded */ +}; + +static int lastx=-1; +static int lasty=-1; + +static Vctlr* +init(Vctlr* vctlr, int x, int y, int d) +{ + USED(vctlr,x,y,d); + + return &FSV; +} + +static int +setcolour(ulong p, ulong r, ulong g, ulong b) +{ + if(gscreen.ldepth == 0) + return 0; /* can't change mono screen colormap */ + else{ + vid->addr = p << 24; + vid->color = r << 24; + vid->color = g << 24; + vid->color = b << 24; + return 1; + } +} + +static ulong backingstore[64]; +static Memdata backingstoredata = { + nil, + backingstore +}; + +static ulong backingnocursor[64]; +static Memdata backingnocursordata = { + nil, + backingnocursor +}; + +static ulong backwithcursor[64]; +static Memdata backwithcursordata = { + nil, + backwithcursor +}; + +static Memimage backingnocursormem = { + {0,0,16,16}, + {0,0,16,16}, + 3, + 0, + &backingnocursordata, + 0, + 16/4, + 0, + 0, +}; +static Memimage backingmem = { + {0,0,16,16}, + {0,0,16,16}, + 3, + 0, + &backingstoredata, + 0, + 16/4, + 0, + 0, +}; + +static void +disable(void) +{ + if(FSV.hidecount++) + return; + if(lastx < 0 || lasty < 0) + return; + + memimagedraw(&gscreen, Rect(lastx,lasty,lastx+16,lasty+16), + &backingnocursormem, Pt(0,0), memones, Pt(0,0)); +} + +static void +enable(void) +{ + uchar *p; + uchar mask; + uchar *cset; + int i; + + if(--FSV.hidecount > 0) + return; + FSV.hidecount = 0; + + if(lastx < 0 || lasty < 0) + return; + + memimagedraw(&backingmem,Rect(0,0,16,16),&gscreen,Pt(lastx,lasty),memones, + Pt(0,0)); + + memcpy(backingnocursor,backingstore,256); + p = (uchar*)backingmem.data->data; + + cset = FSV.cursor.set; + + for(i=0;i<32;i++) { + mask = ~cset[i]; + + if(!(mask&(1<<7))) *p = 0xff; + ++p; + if(!(mask&(1<<6))) *p = 0xff; + ++p; + if(!(mask&(1<<5))) *p = 0xff; + ++p; + if(!(mask&(1<<4))) *p = 0xff; + ++p; + if(!(mask&(1<<3))) *p = 0xff; + ++p; + if(!(mask&(1<<2))) *p = 0xff; + ++p; + if(!(mask&(1<<1))) *p = 0xff; + ++p; + if(!(mask&(1<<0))) *p = 0xff; + ++p; + } + + memimagedraw(&gscreen,Rect(lastx,lasty,lastx+16,lasty+16),&backingmem,Pt(0,0), + memones,Pt(0,0)); +} + +static void +move(int cx, int cy) +{ + if(!FSV.loaded) + return; + + disable(); + cursorupdate0(); + lastx = cx; + lasty = cy; + enable(); +} + + +static void +load(Cursor *curs) +{ + FSV.cursor = *curs; + FSV.loaded=1; +} + +static int +isloaded(void) +{ + return FSV.loaded; +} diff --git a/os/js/io.h b/os/js/io.h new file mode 100644 index 00000000..c3868eb2 --- /dev/null +++ b/os/js/io.h @@ -0,0 +1,224 @@ +/* + * most device registers are memory mapped, but + * a few things are accessed using putphys/getphys + */ +#define SBUS(n) (0x30000000+(n)*0x10000000) +#define FRAMEBUF(n) SBUS(n) +#define FRAMEBUFID(n) (SBUS(n)+0x000000) +#define DISPLAYRAM(n) (SBUS(n)+0x800000) +#define CLOCK 0x71D00000 +#define CLOCKFREQ 1000000 /* one microsecond increments */ + +#define SUPERIO_PHYS_PAGE 0x71300000 +#define SUPERIO_INDEX_OFFSET 0x398 +#define SUPERIO_DATA_OFFSET 0x399 +#define SUPERIO_MOUSE_KBD_DATA_PORT 0x60 +#define SUPERIO_MOUSE_KBD_CTL_PORT 0x64 + +#define AUDIO_PHYS_PAGE 0x66666666 +#define AUDIO_INDEX_OFFSET 0x830 + +enum +{ + Mousevec = 13, + Kbdvec = 13 +}; + +#define NVR_CKSUM_PHYS 0x71200000 /* non-volatile RAM cksum page */ +#define NVR_PHYS 0x71201000 /* non-volatile RAM */ +#define DMA 0x78400000 /* SCSI and Ether DMA registers */ +#define SCSI 0x78800000 /* NCR53C90 registers */ +#define ETHER 0x78C00000 /* RDP, RAP */ +#define FLOPPY 0x71400000 +#define SYSINTR 0x71E10000 /* system interrupt control registers */ + +#define TIMECONFIG 0x71D10010 /* timer configuration register (phys) */ +#define AUXIO1 0x71900000 +#define AUXIO2 0x71910000 + +typedef struct Sysint Sysint; +struct Sysint +{ + ulong pending; + ulong mask; + ulong maskclr; + ulong maskset; + ulong target; +}; + +enum { + MaskAllIntr = 1<<31, + MEIntr = 1<<30, + MSIIntr = 1<<29, + EMCIntr = 1<<28, + VideoIntr = 1<<20, /* supersparc only */ + Timer10 = 1<<19, + EtherIntr = 1<<16, + SCCIntr = 1<<15, + KbdIntr = 1<<13, + /* bits 7 to 13 are SBUS levels 1 to 7 */ +}; +#define SBUSINTR(x) (1<<((x)+6)) + +typedef struct SCCdev SCCdev; +struct SCCdev +{ + uchar ptrb; + uchar dummy1; + uchar datab; + uchar dummy2; + uchar ptra; + uchar dummy3; + uchar dataa; + uchar dummy4; +}; + +/* + * non-volatile ram + */ +#define NVREAD (4096-32) /* minus RTC */ +#define NVWRITE (0x800) /* */ +#define IDOFF (4096-8-32) + +/* + * real-time clock + */ +typedef struct RTCdev RTCdev; +struct RTCdev +{ + uchar control; /* read or write the device */ + uchar sec; + uchar min; + uchar hour; + uchar wday; + uchar mday; + uchar mon; + uchar year; +}; +#define RTCOFF 0xFF8 +#define RTCREAD (0x40) +#define RTCWRITE (0x80) + +/* + * dma + */ +typedef struct DMAdev DMAdev; +struct DMAdev { + /* ESP/SCSI DMA */ + ulong csr; /* Control/Status */ + ulong addr; /* address in 16Mb segment */ + ulong count; /* transfer byte count */ + ulong diag; + + /* Ether DMA */ + ulong ecsr; /* Control/Status */ + ulong ediag; + ulong cache; /* cache valid bits */ + uchar base; /* base address (16Mb segment) */ +}; + +enum { + Int_pend = 0x00000001, /* interrupt pending */ + Err_pend = 0x00000002, /* error pending */ + Pack_cnt = 0x0000000C, /* pack count (mask) */ + Int_en = 0x00000010, /* interrupt enable */ + Dma_Flush = 0x00000020, /* flush pack end error */ + Drain = 0x00000040, /* drain pack to memory */ + Dma_Reset = 0x00000080, /* hardware reset (sticky) */ + Write = 0x00000100, /* set for device to memory (!) */ + En_dma = 0x00000200, /* enable DMA */ + Req_pend = 0x00000400, /* request pending */ + Byte_addr = 0x00001800, /* next byte addr (mask) */ + En_cnt = 0x00002000, /* enable count */ + Tc = 0x00004000, /* terminal count */ + Ilacc = 0x00008000, /* which ether chip */ + Dev_id = 0xF0000000, /* device ID */ +}; + +/* + * NCR53C90 SCSI controller (every 4th location) + */ +typedef struct SCSIdev SCSIdev; +struct SCSIdev { + uchar countlo; /* byte count, low bits */ + uchar pad1[3]; + uchar countmi; /* byte count, middle bits */ + uchar pad2[3]; + uchar fifo; /* data fifo */ + uchar pad3[3]; + uchar cmd; /* command byte */ + uchar pad4[3]; + union { + struct { /* read only... */ + uchar status; /* status */ + uchar pad05[3]; + uchar intr; /* interrupt status */ + uchar pad06[3]; + uchar step; /* sequence step */ + uchar pad07[3]; + uchar fflags; /* fifo flags */ + uchar pad08[3]; + uchar config; /* RW: configuration */ + uchar pad09[3]; + uchar Reserved1; + uchar pad0A[3]; + uchar Reserved2; + uchar pad0B[3]; + uchar conf2; /* RW: configuration */ + uchar pad0C[3]; + uchar conf3; /* RW: configuration */ + uchar pad0D[3]; + uchar partid; /* unique part id */ + uchar pad0E[3]; + uchar fbottom; /* RW: fifo bottom */ + uchar pad0F[3]; + }; + struct { /* write only... */ + uchar destid; /* destination id */ + uchar pad15[3]; + uchar timeout; /* during selection */ + uchar pad16[3]; + uchar syncperiod; /* synchronous xfr period */ + uchar pad17[3]; + uchar syncoffset; /* synchronous xfr offset */ + uchar pad18[3]; + uchar RW0; + uchar pad19[3]; + uchar clkconf; + uchar pad1A[3]; + uchar test; + uchar pad1B[3]; + uchar RW1; + uchar pad1C[3]; + uchar RW2; + uchar pad1D[3]; + uchar counthi; /* byte count, hi bits */ + uchar pad1E[3]; + uchar RW3; + uchar pad1F[3]; + }; + }; +}; + +/* + * DMA2 ENET + */ +enum { + E_Int_pend = 0x00000001, /* interrupt pending */ + E_Err_pend = 0x00000002, /* error pending */ + E_draining = 0x0000000C, /* E-cache draining */ + E_Int_en = 0x00000010, /* interrupt enable */ + E_Invalidate = 0x00000020, /* mark E-cache invalid */ + E_Slave_err = 0x00000040, /* slave access size error (sticky) */ + E_Reset = 0x00000080, /* invalidate cache & reset interface (sticky) */ + E_Drain = 0x00000400, /* force draining of E-cache to memory */ + E_Dsbl_wr_drn = 0x00000800, /* disable E-cache drain on descriptor writes from ENET */ + E_Dsbl_rd_drn = 0x00001000, /* disable E-cache drain on slave reads to ENET */ + E_Ilacc = 0x00008000, /* `modifies ENET DMA cycle' */ + E_Dsbl_buf_wr = 0x00010000, /* disable buffering of slave writes to ENET */ + E_Dsbl_wr_inval = 0x00020000, /* do not invalidate E-cache on slave writes */ + E_Burst_size = 0x000C0000, /* DMA burst size */ + E_Loop_test = 0x00200000, /* loop back mode */ + E_TP_select = 0x00400000, /* zero for AUI mode */ + E_Dev_id = 0xF0000000, /* device ID */ +}; diff --git a/os/js/iob.c b/os/js/iob.c new file mode 100644 index 00000000..4873847e --- /dev/null +++ b/os/js/iob.c @@ -0,0 +1,13 @@ +#include "u.h" + +void +outb(ulong addr, uchar val) +{ + *(uchar*)addr = val; +} + +uchar +inb(ulong addr) +{ + return *(uchar*)addr; +} diff --git a/os/js/js b/os/js/js new file mode 100644 index 00000000..16e2ff64 --- /dev/null +++ b/os/js/js @@ -0,0 +1,104 @@ +dev + root + cons + env + mnt + pipe + prog + rtc + srv + dup + ssl + draw + pointer + + ip bootp ip ipv6 ipaux iproute arp netlog ptclbsum iprouter plan9 nullmedium pktmedium + lance netif netaux ethermedium + + ns16552 + tinyfs + cap +# cs4231 A + +ip +# il + tcp + udp +# rudp +# igmp + ipifc + icmp + icmp6 + ipmux + +lib + interp + tk + prefab + draw + memlayer + memdraw + keyring + sec + mp + kern +# math + +mod + sys + draw + prefab + tk + keyring + +link + pppmedium ppp compress + +init + jsinit + + +port + alarm + alloc + allocb + chan + dev + dial + dis + discall + exception + exportfs + inferno + latin1 + nocache + parse + pgrp + print + proc + qio + qlock + sysfile + taslock + xalloc + +code + int kernel_pool_pcnt = 10; + int main_pool_pcnt = 40; + int heap_pool_pcnt = 20; + int image_pool_pcnt = 40; + int consoleprint = 1; + int cflag = 1; + + +root + /chan / + /dev / + /dis + /env / + /fd / + /n + /net / + /nvfs / + /prog / + /osinit.dis diff --git a/os/js/kbd.c b/os/js/kbd.c new file mode 100644 index 00000000..38bae986 --- /dev/null +++ b/os/js/kbd.c @@ -0,0 +1,482 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +enum +{ + Data= 0x60, /* data port */ + + Status= 0x64, /* status port */ + Inready= 0x01, /* input character ready */ + Outbusy= 0x02, /* output busy */ + Sysflag= 0x04, /* system flag */ + Cmddata= 0x08, /* cmd==0, data==1 */ + Inhibit= 0x10, /* keyboard/mouse inhibited */ + Minready= 0x20, /* mouse character ready */ + Rtimeout= 0x40, /* general timeout */ + Parity= 0x80, + + Cmd= 0x64, /* command port (write only) */ + + CTdata= 0x0, /* chips & Technologies ps2 data port */ + CTstatus= 0x1, /* chips & Technologies ps2 status port */ + Enable= 1<<7, + Clear= 1<<6, + Error= 1<<5, + Intenable= 1<<4, + Reset= 1<<3, + Tready= 1<<2, + Rready= 1<<1, + Idle= 1<<0, + + Spec= 0x80, + + PF= Spec|0x20, /* num pad function key */ + View= Spec|0x00, /* view (shift window up) */ + KF= Spec|0x40, /* function key */ + Shift= Spec|0x60, + Break= Spec|0x61, + Ctrl= Spec|0x62, + Latin= Spec|0x63, + Caps= Spec|0x64, + Num= Spec|0x65, + Middle= Spec|0x66, + No= 0x00, /* peter */ + + Home= KF|13, + Up= KF|14, + Pgup= KF|15, + Print= KF|16, + Left= View, + Right= View, + End= '\r', + Down= View, + Pgdown= View, + Ins= KF|20, + Del= 0x7F, + + Rbutton=4, + Mbutton=2, + Lbutton=1, +}; + +uchar +kbtab[] = { +[0x00] No, 0x1b, '1', '2', '3', '4', '5', '6', +[0x08] '7', '8', '9', '0', '-', '=', '\b', '\t', +[0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', +[0x18] 'o', 'p', '[', ']', '\n', Ctrl, 'a', 's', +[0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', +[0x28] '\'', '`', Shift, '\\', 'z', 'x', 'c', 'v', +[0x30] 'b', 'n', 'm', ',', '.', '/', Shift, '*', +[0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5, +[0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, KF|12, '7', +[0x48] '8', '9', '-', '4', '5', '6', '+', '1', +[0x50] '2', '3', '0', '.', No, No, No, KF|11, +[0x58] KF|12, No, No, No, No, No, No, No, +}; + +uchar +kbtabshift[] = { +[0x00] No, 0x1b, '!', '@', '#', '$', '%', '^', +[0x08] '&', '*', '(', ')', '_', '+', '\b', '\t', +[0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', +[0x18] 'O', 'P', '{', '}', '\n', Ctrl, 'A', 'S', +[0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', +[0x28] '"', '~', Shift, '|', 'Z', 'X', 'C', 'V', +[0x30] 'B', 'N', 'M', '<', '>', '?', Shift, '*', +[0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5, +[0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, KF|12, '7', +[0x48] '8', '9', '-', '4', '5', '6', '+', '1', +[0x50] '2', '3', '0', '.', No, No, No, KF|11, +[0x58] KF|12, No, No, No, No, No, No, No, +}; + +uchar +kbtabesc1[] = { +[0x00] No, No, No, No, No, No, No, No, +[0x08] No, No, No, No, No, No, No, No, +[0x10] No, No, No, No, No, No, No, No, +[0x18] No, No, No, No, '\n', Ctrl, No, No, +[0x20] No, No, No, No, No, No, No, No, +[0x28] No, No, Shift, No, No, No, No, No, +[0x30] No, No, No, No, No, '/', No, Print, +[0x38] Latin, No, No, No, No, No, No, No, +[0x40] No, No, No, No, No, No, Break, Home, +[0x48] Up, Pgup, No, Left, No, Right, No, End, +[0x50] Down, Pgdown, Ins, Del, No, No, No, No, +[0x58] No, No, No, No, No, No, No, No, +}; + +static int keybuttons; +static uchar ccc; +static int shift; + +enum +{ + /* controller command byte */ + Cscs1= (1<<6), /* scan code set 1 */ + Cmousedis= (1<<5), /* mouse disable */ + Ckbddis= (1<<4), /* kbd disable */ + Csf= (1<<2), /* system flag */ + Cmouseint= (1<<1), /* mouse interrupt enable */ + Ckbdint= (1<<0), /* kbd interrupt enable */ +}; + +/* + * wait for output no longer busy + */ +static int +outready(void) +{ + int tries; + + for(tries = 0; (superio_readctl() & Outbusy); tries++){ + if(tries > 500) + return -1; + microdelay(2); + } + return 0; +} + +/* + * wait for input + */ +static int +inready(void) +{ + int tries; + + for(tries = 0; !(superio_readctl() & Inready); tries++){ + if(tries > 500) + return -1; + microdelay(2); + } + return 0; +} + +/* + * send a command to the mouse + */ +static int +mousecmd(int cmd) +{ + unsigned int c; + int tries; + + c = 0; + tries = 0; + do{ + if(tries++ > 2) + break; + if(outready() < 0) + break; + superio_writectl(0xD4); + if(outready() < 0) + break; + superio_writedata(cmd); + if(outready() < 0) + break; + if(inready() < 0) + break; + c = superio_readdata(); + } while(c == 0xFE || c == 0); + + if(c != 0xFA){ + print("mouse returns %2.2ux to the %2.2ux command\n", c, cmd); + return -1; + } + return 0; +} + +/* + * ask 8042 to enable the use of address bit 20 + */ +void +i8042a20(void) +{ + outready(); + superio_writectl(0xD1); + outready(); + superio_writedata(0xDF); + outready(); +} + +/* + * ask 8042 to reset the machine + */ +void +i8042reset(void) +{ + ushort *s = (ushort*)(KZERO|0x472); + int i, x; + + *s = 0x1234; /* BIOS warm-boot flag */ + + /* + * newer reset the machine command + */ + outready(); + superio_writectl(0xFE); + outready(); + + /* + * Pulse it by hand (old somewhat reliable) + */ + x = 0xDF; + for(i = 0; i < 5; i++){ + x ^= 1; + outready(); + superio_writectl(0xD1); + outready(); + superio_writedata(x); /* toggle reset */ + microdelay(100); + } +} + +/* + * ps/2 mouse message is three bytes + * + * byte 0 - 0 0 SDY SDX 1 M R L + * byte 1 - DX + * byte 2 - DY + * + * shift & left button is the same as middle button + */ +static int +ps2mouseputc(int c) +{ + static short msg[3]; + static int nb; + static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 5, 2, 3, 6, 7 }; + int buttons, dx, dy; + + /* + * check byte 0 for consistency + */ + if(nb==0 && (c&0xc8)!=0x08) + return 0; + + msg[nb] = c; + if(++nb == 3) { + nb = 0; + if(msg[0] & 0x10) + msg[1] |= 0xFF00; + if(msg[0] & 0x20) + msg[2] |= 0xFF00; + + buttons = b[(msg[0]&7) | (shift ? 8 : 0)] | keybuttons; + dx = msg[1]; + dy = -msg[2]; + mousetrack(buttons, dx, dy, 1); + } + return 0; +} + +/* + * keyboard interrupt + */ +void +kbdintr(void) +{ + int s, c, i; + static int esc1, esc2; + static int caps; + static int ctl; + static int num; + static int collecting, nk; + static int alt; + static Rune kc[5]; + int keyup; + + /* + * get status + */ + s = superio_readctl(); + if(!(s&Inready)) + return; + + /* + * get the character + */ + c = superio_readdata(); + + /* + * if it's the mouse... + */ + if(s & Minready) { + ps2mouseputc(c); + return; + } + + /* + * e0's is the first of a 2 character sequence + */ + if(c == 0xe0){ + esc1 = 1; + return; + } else if(c == 0xe1){ + esc2 = 2; + return; + } + + keyup = c&0x80; + c &= 0x7f; + if(c > sizeof kbtab){ +/* print("unknown key %ux\n", c|keyup); */ + return; + } + + if(esc1){ + c = kbtabesc1[c]; + esc1 = 0; + } else if(esc2){ + esc2--; + return; + } else if(shift) + c = kbtabshift[c]; + else + c = kbtab[c]; + + if(caps && c<='z' && c>='a') + c += 'A' - 'a'; + + /* + * keyup only important for shifts + */ + if(keyup){ + switch(c){ + case Latin: + alt = 0; + break; + case Shift: + shift = 0; + break; + case Ctrl: + ctl = 0; + break; + } + return; + } + + /* + * normal character + */ + if(!(c & Spec)){ + if(ctl){ + if(alt && c == Del) + exit(0); + c &= 0x1f; + } + if(!collecting){ + kbdputc(kbdq, c); + return; + } + kc[nk++] = c; + c = latin1(kc, nk); + if(c < -1) /* need more keystrokes */ + return; + if(c != -1) /* valid sequence */ + kbdputc(kbdq, c); + else /* dump characters */ + for(i=0; i<nk; i++) + kbdputc(kbdq, kc[i]); + nk = 0; + collecting = 0; + return; + } else { + switch(c){ + case Caps: + caps ^= 1; + return; + case Num: + num ^= 1; + return; + case Shift: + shift = 1; + return; + case Latin: + alt = 1; + collecting = 1; + nk = 0; + return; + case Ctrl: + ctl = 1; + return; + } + } + kbdputc(kbdq, c); +} + +/* + * set up a ps2 mouse + */ +static void +ps2mouse(void) +{ + int x; + + /* enable kbd/mouse xfers and interrupts */ + x = splhi(); + ccc &= ~Cmousedis; + ccc |= Cmouseint; + if(outready() < 0) + print("mouse init failed\n"); + superio_writectl(0x60); + if(outready() < 0) + print("mouse init failed\n"); + superio_writedata(ccc); + if(outready() < 0) + print("mouse init failed\n"); + superio_writectl(0xA8); + if(outready() < 0){ + splx(x); + return; + } + + /* make mouse streaming, enabled */ + mousecmd(0xEA); + mousecmd(0xF4); + splx(x); +} + +void +kbdinit(void) +{ + int c; + + kbdq = qopen(4*1024, 0, 0, 0); + qnoblock(kbdq, 1); + + /* wait for a quiescent controller */ + while((c = superio_readctl()) & (Outbusy | Inready)) + if(c & Inready) + superio_readdata(); + + /* get current controller command byte */ + superio_writectl(0x20); + if(inready() < 0){ + print("kbdinit: can't read ccc\n"); + ccc = 0; + } else + ccc = superio_readdata(); + + /* enable kbd xfers and interrupts */ + /* disable mouse */ + ccc &= ~Ckbddis; + ccc |= Csf | Ckbdint | Cscs1 | Cmousedis; + if(outready() < 0) + print("kbd init failed\n"); + superio_writectl(0x60); + if(outready() < 0) + print("kbd init failed\n"); + superio_writedata(ccc); + outready(); + + /* Assume ps2 mouse */ + ps2mouse(); +} diff --git a/os/js/l.s b/os/js/l.s new file mode 100644 index 00000000..b8eb8e0c --- /dev/null +++ b/os/js/l.s @@ -0,0 +1,560 @@ +#include "mem.h" + +#define SYSPSR (PSREF|PSRET|PSRSUPER|SPL(15)) +#define NOOP ORN R0, R0; ORN R0, R0; ORN R0, R0; ORN R0, R0; ORN R0, R0 +#define FLUSH WORD $0x81d80000 /* IFLUSH (R0) */ + +#define MMUASI 0x4 +#define TLBASI 0x3 +#define IFLUSHASI 0x36 +#define DFLUSHASI 0x37 +#define PHYSASI 0x20 /* MMU bypass */ +#define CTLASI 0x20 /* 0x2F on bigger sun4M */ + +TEXT start(SB), $-4 + /* get virtual, fast */ + + /* copy ROM's L1 page table entries, mapping VA:0 and VA:KZERO to PA:0 */ + MOVW $setSB(SB), R2 + + MOVW $CTPR, R7 + MOVW (R7, MMUASI), R5 + SLL $4, R5, R5 + MOVW (R5, PHYSASI), R5 /* context table entry 0 */ + SRL $4, R5, R5 + SLL $8, R5, R5 /* to physical pointer */ + + MOVW $(((KZERO>>24)&0xFF)*4), R4 /* KZERO base in level 1 ptab */ + MOVW (R5, PHYSASI), R6 /* L1 region 0 set by boot */ + ADD R4,R5,R10 + MOVW R6, (R10, PHYSASI) /* map KZERO */ + + ADD $4, R5 + MOVW (R5, PHYSASI), R6 + ADD R4, R5, R10 + MOVW R6, (R10, PHYSASI) /* map KZERO+16Mbytes */ + + /* now mapped correctly. jmpl to where we want to be */ + + MOVW $startvirt(SB), R7 + JMPL (R7) + RETURN /* can't get here */ + +TEXT startvirt(SB), $-4 + MOVW $edata(SB),R9 + MOVW $end(SB),R10 +clrbss: + MOVW R0,(R9) + ADD $4, R9 + CMP R9, R10 + BNE clrbss + NOOP + + MOVW $rom(SB), R7 + MOVW R8, (R7) /* romvec passed in %i0==R8 */ + + /* turn off the cache but ensure ITBR enabled */ + MOVW (R0, MMUASI), R7 + ANDN $(ENABCACHE|ITBRDISABLE), R7 + MOVW R7, (R0, MMUASI) + + FLUSH + NOOP + + + MOVW $MID, R7 /* disable Sbus DMA */ + MOVW (R7, PHYSASI), R8 + ANDN $(0x1E<<15), R8 + MOVW R8, (R7, PHYSASI) + + MOVW $BOOTSTACK, R1 + + MOVW $(SPL(0xF)|PSREF|PSRSUPER), R7 + OR $PSRET, R7 /* allow rom use while debugging ... */ + MOVW R7, PSR + + MOVW $(0x35<<22), R7 /* NVM OFM DZM NS */ + MOVW R7, fsr+0(SB) + MOVW $fsr+0(SB), R8 + MOVW (R8), FSR + FMOVD $0.5, F26 /* 0.5 -> F26 */ + FSUBD F26, F26, F24 /* 0.0 -> F24 */ + FADDD F26, F26, F28 /* 1.0 -> F28 */ + FADDD F28, F28, F30 /* 2.0 -> F30 */ + + FMOVD F24, F0 + FMOVD F24, F2 + FMOVD F24, F4 + FMOVD F24, F6 + FMOVD F24, F8 + FMOVD F24, F10 + FMOVD F24, F12 + FMOVD F24, F14 + FMOVD F24, F16 + FMOVD F24, F18 + FMOVD F24, F20 + FMOVD F24, F22 + + MOVW $mach0(SB), R(MACH) +/* MOVW $0x8, R7 /**/ + MOVW R0, WIM + + JMPL main(SB) + MOVW (R0), R0 + RETURN + +TEXT call0(SB), $-4 + JMPL (R0) + JMPL (R0) + JMPL (R0) + JMPL (R0) + RETURN + +TEXT getcinfo(SB), $0 + MOVW (R7, 0x0C), R7 + RETURN + +TEXT flushiline(SB), $0 + MOVW R0, (R7, 0x0C) + NOOP + RETURN + +TEXT flushdline(SB), $0 + MOVW R0, (R7, 0x0E) + NOOP + RETURN + +TEXT getphys(SB), $0 + + MOVW (R7, PHYSASI), R7 + RETURN + +TEXT putphys(SB), $0 + + MOVW 4(FP), R8 + MOVW R8, (R7, PHYSASI) + RETURN + +TEXT getrmmu(SB), $0 + + MOVW (R7, MMUASI), R7 + RETURN + +TEXT putrmmu(SB), $0 + + MOVW 4(FP), R8 + MOVW R8, (R7, MMUASI) + RETURN + +TEXT getpcr(SB), $0 + + MOVW (R0, MMUASI), R7 + RETURN + +TEXT setpcr(SB), $0 + + MOVW R7, (R0, MMUASI) + FLUSH /* `strongly recommended' after STA to PCR */ + NOOP + RETURN + +TEXT _tas(SB), $0 + + TAS (R7), R7 /* LDSTUB, thank you ken */ + RETURN + +#ifdef notdef +TEXT _tas(SB), $0 /* it seems we must be splhi */ + + MOVW PSR, R8 + MOVW $SYSPSR, R9 + MOVW R9, PSR + NOOP + TAS (R7), R7 /* LDSTUB, thank you ken */ + MOVW R8, PSR + NOOP + RETURN +#endif + +TEXT softtas(SB), $0 /* all software; avoid LDSTUB */ + + MOVW PSR, R8 + MOVW $SYSPSR, R9 + MOVW R9, PSR + NOOP + MOVB (R7), R10 + CMP R10, R0 + BE gotit + /* cache is write through, no need to flush */ + MOVW $0xFF, R7 + MOVW R8, PSR + NOOP + RETURN + +gotit: + MOVW $0xFF, R10 + MOVB R10, (R7) + /* cache is write through, no need to flush */ + MOVW $0, R7 + MOVW R8, PSR + NOOP + RETURN + +TEXT spllo(SB), $0 + + MOVW PSR, R7 + MOVW R7, R10 + ANDN $SPL(15), R10 + MOVW R10, PSR + NOOP + RETURN + +TEXT splhi(SB), $0 + + MOVW R15, 4(R(MACH)) /* save PC in m->splpc */ + MOVW PSR, R7 + MOVW R7, R10 + OR $SPL(15), R10 + MOVW R10, PSR + NOOP + RETURN + +TEXT splxpc(SB), $0 + + MOVW R7, PSR /* BUG: book says this is buggy */ + NOOP + RETURN + + +TEXT splx(SB), $0 + + MOVW R15, 4(R(MACH)) /* save PC in m->splpc */ + MOVW R7, PSR /* BUG: book says this is buggy */ + NOOP + RETURN +TEXT spldone(SB), $0 + + RETURN + +TEXT rfnote(SB), $0 + + MOVW R7, R1 /* 1st arg is &uregpointer */ + ADD $4, R1 /* point at ureg */ + JMP restore + +TEXT traplink(SB), $-4 + + /* R8 to R23 are free to play with */ + /* R17 contains PC, R18 contains nPC */ + /* R19 has PSR loaded from vector code */ + + ANDCC $PSRPSUPER, R19, R0 + BE usertrap + +kerneltrap: + /* + * Interrupt or fault from kernel + */ + ANDN $7, R1, R20 /* dbl aligned */ + MOVW R1, (0-(4*(32+6))+(4*1))(R20) /* save R1=SP */ + /* really clumsy: store these in Ureg so can be restored below */ + MOVW R2, (0-(4*(32+6))+(4*2))(R20) /* SB */ + MOVW R5, (0-(4*(32+6))+(4*5))(R20) /* USER */ + MOVW R6, (0-(4*(32+6))+(4*6))(R20) /* MACH */ + SUB $(4*(32+6)), R20, R1 + +trap1: + MOVW Y, R20 + MOVW R20, (4*(32+0))(R1) /* Y */ + MOVW TBR, R20 + MOVW R20, (4*(32+1))(R1) /* TBR */ + AND $~0x1F, R19 /* force CWP=0 */ + MOVW R19, (4*(32+2))(R1) /* PSR */ + MOVW R18, (4*(32+3))(R1) /* nPC */ + MOVW R17, (4*(32+4))(R1) /* PC */ + MOVW R0, (4*0)(R1) + MOVW R3, (4*3)(R1) + MOVW R4, (4*4)(R1) + MOVW R7, (4*7)(R1) + RESTORE R0, R0 + /* now our registers R8-R31 are same as before trap */ + /* save registers two at a time */ + MOVD R8, (4*8)(R1) + MOVD R10, (4*10)(R1) + MOVD R12, (4*12)(R1) + MOVD R14, (4*14)(R1) + MOVD R16, (4*16)(R1) + MOVD R18, (4*18)(R1) + MOVD R20, (4*20)(R1) + MOVD R22, (4*22)(R1) + MOVD R24, (4*24)(R1) + MOVD R26, (4*26)(R1) + MOVD R28, (4*28)(R1) + MOVD R30, (4*30)(R1) + /* SP and SB and u and m are already set; away we go */ + MOVW R1, R7 /* pointer to Ureg */ + SUB $8, R1 + MOVW $SYSPSR, R8 + MOVW R8, PSR + NOOP + JMPL trap(SB) + + ADD $8, R1 +restore: + MOVW (4*(32+2))(R1), R8 /* PSR */ + MOVW R8, PSR + NOOP + + MOVD (4*30)(R1), R30 + MOVD (4*28)(R1), R28 + MOVD (4*26)(R1), R26 + MOVD (4*24)(R1), R24 + MOVD (4*22)(R1), R22 + MOVD (4*20)(R1), R20 + MOVD (4*18)(R1), R18 + MOVD (4*16)(R1), R16 + MOVD (4*14)(R1), R14 + MOVD (4*12)(R1), R12 + MOVD (4*10)(R1), R10 + MOVD (4*8)(R1), R8 + SAVE R0, R0 + MOVD (4*6)(R1), R6 + MOVD (4*4)(R1), R4 + MOVD (4*2)(R1), R2 + MOVW (4*(32+0))(R1), R20 /* Y */ + MOVW R20, Y + MOVW (4*(32+4))(R1), R17 /* PC */ + MOVW (4*(32+3))(R1), R18 /* nPC */ + MOVW (4*1)(R1), R1 /* restore R1=SP */ + RETT R17, R18 + +usertrap: + /* + * Interrupt or fault from user + */ + MOVW R1, R8 + MOVW R2, R9 + MOVW $setSB(SB), R2 + MOVW $(USERADDR+BY2PG), R1 + MOVW R8, (0-(4*(32+6))+(4*1))(R1) /* save R1=SP */ + MOVW R9, (0-(4*(32+6))+(4*2))(R1) /* save R2=SB */ + MOVW R5, (0-(4*(32+6))+(4*5))(R1) /* save R5=USER */ + MOVW R6, (0-(4*(32+6))+(4*6))(R1) /* save R6=MACH */ + MOVW $USERADDR, R(USER) + MOVW $mach0(SB), R(MACH) + SUB $(4*(32+6)), R1 + JMP trap1 + +TEXT puttbr(SB), $0 + MOVW R7, TBR + NOOP + RETURN + +TEXT gettbr(SB), $0 + + MOVW TBR, R7 + RETURN + +TEXT r1(SB), $0 + + MOVW R1, R7 + RETURN + +TEXT getwim(SB), $0 + + MOVW WIM, R7 + RETURN + +TEXT setlabel(SB), $0 + + MOVW R1, (R7) + MOVW R15, 4(R7) + MOVW $0, R7 + RETURN + +TEXT gotolabel(SB), $0 + + MOVW (R7), R1 + MOVW 4(R7), R15 + MOVW $1, R7 + RETURN + +TEXT getpsr(SB), $0 + + MOVW PSR, R7 + RETURN + +TEXT setpsr(SB), $0 + + MOVW R7, PSR + NOOP + RETURN + +TEXT savefpregs(SB), $0 + + MOVD F0, (0*4)(R7) + MOVD F2, (2*4)(R7) + MOVD F4, (4*4)(R7) + MOVD F6, (6*4)(R7) + MOVD F8, (8*4)(R7) + MOVD F10, (10*4)(R7) + MOVD F12, (12*4)(R7) + MOVD F14, (14*4)(R7) + MOVD F16, (16*4)(R7) + MOVD F18, (18*4)(R7) + MOVD F20, (20*4)(R7) + MOVD F22, (22*4)(R7) + MOVD F24, (24*4)(R7) + MOVD F26, (26*4)(R7) + MOVD F28, (28*4)(R7) + MOVD F30, (30*4)(R7) + MOVW FSR, (34*4)(R7) + + MOVW PSR, R8 + ANDN $PSREF, R8 + MOVW R8, PSR + RETURN + +TEXT savefsr(SB), $0 + MOVW FSR, 0(R7) + RETURN + +TEXT restfsr(SB), $0 + MOVW 0(R7), FSR + RETURN + + +TEXT fpinit(SB), $0 + MOVW PSR, R8 + OR $PSREF, R8 + MOVW R8, PSR + RETURN + +TEXT disabfp(SB), $0 + + MOVW PSR, R8 + ANDN $PSREF, R8 + MOVW R8, PSR + RETURN + +TEXT restfpregs(SB), $0 + + MOVW PSR, R8 + OR $PSREF, R8 + MOVW R8, PSR + + NOOP /* wait for PSR to quiesce */ + + + MOVD (0*4)(R7), F0 + MOVD (2*4)(R7), F2 + MOVD (4*4)(R7), F4 + MOVD (6*4)(R7), F6 + MOVD (8*4)(R7), F8 + MOVD (10*4)(R7), F10 + MOVD (12*4)(R7), F12 + MOVD (14*4)(R7), F14 + MOVD (16*4)(R7), F16 + MOVD (18*4)(R7), F18 + MOVD (20*4)(R7), F20 + MOVD (22*4)(R7), F22 + MOVD (24*4)(R7), F24 + MOVD (26*4)(R7), F26 + MOVD (28*4)(R7), F28 + MOVD (30*4)(R7), F30 + MOVW (34*4)(R7), FSR + + ANDN $PSREF, R8 + MOVW R8, PSR + RETURN + +TEXT getfpq(SB), $0 + + MOVW R7, R8 /* must be D aligned */ + MOVW $fsr+0(SB), R9 + MOVW $0, R7 +getfpq1: + MOVW FSR, (R9) + MOVW (R9), R10 + ANDCC $(1<<13), R10 /* queue not empty? */ + BE getfpq2 + MOVW (R8), R0 /* SS2 bug fix */ + MOVD FQ, (R8) + ADD $1, R7 + ADD $8, R8 + BA getfpq1 +getfpq2: + RETURN + +TEXT getfsr(SB), $0 + MOVW $fsr+0(SB), R7 + MOVW FSR, (R7) + MOVW (R7), R7 + RETURN + +TEXT clearftt(SB), $0 + MOVW R7, fsr+0(SB) + MOVW $fsr+0(SB), R7 + MOVW (R7), FSR + FMOVF F0, F0 + RETURN + +TEXT getcallerpc(SB), $-4 + MOVW 0(R1), R7 + RETURN + +TEXT icflush(SB), $-4 +JMPL (R0) + MOVW R0, (R0, IFLUSHASI) + FLUSH /* flush prefetch */ + NOOP + RETURN + +TEXT dcflush(SB), $0 + + MOVW R0, (R0, DFLUSHASI) /* can only flush the lot */ + RETURN + +TEXT flushtlbpage(SB), $0 + + AND $(~(BY2PG-1)), R7 /* type 0 */ + MOVW R0, (R7, TLBASI) + RETURN + +TEXT flushtlbctx(SB), $0 + + MOVW $0x300, R7 + MOVW R0, (R7, TLBASI) + RETURN + +TEXT flushtlb(SB), $0 + + MOVW $0x400, R7 + MOVW R0, (R7, TLBASI) + RETURN + +GLOBL mach0+0(SB), $MACHSIZE +GLOBL fsr+0(SB), $BY2WD + +/* + * Interface to OPEN BOOT ROM. Must save and restore state because + * of different calling conventions. We don't use it, but it's here + * for reference.. + */ + +TEXT call_openboot(SB), $16 + MOVW R1, R14 /* save my SP in their SP */ + MOVW R2, sb-4(SP) + MOVW R(MACH), mach-8(SP) + MOVW R(USER), user-12(SP) + MOVW param1+4(FP), R8 + MOVW param2+8(FP), R9 + MOVW param3+12(FP), R10 + MOVW param4+16(FP), R11 + JMPL (R7) + MOVW R14, R1 /* restore my SP */ + MOVW user-12(SP), R(USER) + MOVW mach-8(SP), R(MACH) + MOVW sb-4(SP), R2 + MOVW R8, R7 /* move their return value into mine */ + RETURN diff --git a/os/js/main.c b/os/js/main.c new file mode 100644 index 00000000..d539ca11 --- /dev/null +++ b/os/js/main.c @@ -0,0 +1,564 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "version.h" + +Mach *m = &mach0; +Proc *up; +int cflag; + +ulong cachetable[1024]; + +Sysint *sysintr; +struct { + uchar format; + uchar type; + uchar ea[6]; + uchar pad[32-8]; +} idprom; + +int cpuserver; +ulong bank[8]; +uchar mempres[64]; +char fbstr[32]; +ulong fbslot; +int usecg6; +Label catch; +uchar *sp; + +int cold=1; + +typedef struct Sysparam Sysparam; +struct Sysparam +{ + int id; /* Model type from id prom */ + char *name; /* System name */ + char ss2; /* Is Sparcstation 2? */ + int vacsize; /* Cache size */ + int vacline; /* Cache line size */ + int ncontext; /* Number of MMU contexts */ + char cachebug; /* Machine needs cache bug work around */ + int nbank; /* Number of banks of memory */ + int banksize; /* Maximum Mbytes per bank */ + int pcnt; /* percent of mem for kernel? */ +} +sysparam[] = +{ + { 0xFF, "unknown Sun4M",0, 0, 0, 64, 0, 4, 32 ,0}, + { 0x80, "JavaStation uSparcII",0, 0, 0, 256, 0, 4, 32 ,2}, + { 0 } +}; +Sysparam *sparam; + +void +doc(char *m) +{ + print("%s\n", m); +} + +static void poolsizeinit(void); + +void +main(void) +{ + + + machinit(); + trapinit(); + quotefmtinstall(); + confinit(); + xinit(); + mmuinit(); + intrinit(); + clockinit(); + printinit(); + screeninit(); + ioinit(); + doc("ioinit..."); + ns16552install(); + poolsizeinit(); + doc("ns16552install..."); + kbdinit(); + doc("kbdinit..."); + cacheinit(); + doc("cacheinit..."); + procinit(); + doc("procinit..."); + putphys(MID, 0x1F<<16); /* enable arbitration */ + links(); + doc("links"); + chandevreset(); + doc("chandevreset..."); + + print("\nInferno Operating System\n"); + print("%s-%s \n\n",VERSION, conffile); + print("JIT Compilation Mode = %d\n",cflag); + + userinit(); + doc("userinit..."); + + /* clear pending processor interrupts */ + putphys(PROCINTCLR, (~0<<17)|(1<<15)); + print("berore schedinit\n"); + schedinit(); +} + +extern int main_pool_pcnt; +extern int heap_pool_pcnt; +extern int image_pool_pcnt; + +static void +poolsizeinit(void) +{ + ulong nb = conf.npage*BY2PG; + + print("Total memory available: %ld K\n",nb/1024); + poolsize(mainmem, (nb*main_pool_pcnt)/100, 0); + poolsize(heapmem, (nb*heap_pool_pcnt)/100, 0); + poolsize(imagmem, (nb*image_pool_pcnt)/100, 1); +} + +void +intrinit(void) +{ + KMap *k; + + /* clear fault status */ + getphys(AFSR); + + k = kmappa(SYSINTR, PTEIO|PTENOCACHE); + sysintr = (Sysint*)VA(k); + + /* mask all interrupts */ + sysintr->maskset = ~0; + + /* allow these */ + sysintr->maskclr=MaskAllIntr|MEIntr|MSIIntr|EMCIntr|EtherIntr|KbdIntr; + + /* clear pending processor interrupts */ + putphys(PROCINTCLR, (~0<<17)|(1<<15)); + +} + +void +systemreset(void) +{ + microdelay(200); + putphys(SYSCTL, getphys(SYSCTL)|1); /* power on reset */ +} + +void +machinit(void) +{ + memset(m, 0, sizeof(Mach)); +} + +void +ioinit(void) +{ + KMap *k; + uchar *sindex; /* superio index */ + uchar *sdata; /* superio data */ + uchar *mkctl; /* superio mouse/kbd ctl register */ + uchar *mkdata; /* superio mouse/kbd data register */ + + + /* enable the uart's on the superio chip */ + k = kmappa(SUPERIO_PHYS_PAGE, PTEIO|PTENOCACHE); + sindex = (uchar*)(VA(k)+SUPERIO_INDEX_OFFSET); + sdata = (uchar*)(VA(k)+SUPERIO_DATA_OFFSET); + mkdata = (uchar*)(VA(k)+SUPERIO_MOUSE_KBD_DATA_PORT); + mkctl = (uchar*)(VA(k)+SUPERIO_MOUSE_KBD_CTL_PORT); + + superioinit(VA(k),sindex,sdata,mkctl,mkdata); + doc("superioinit..."); +} + +void +init0(void) +{ + Osenv *o; + + up->nerrlab = 0; + + print("before spllo"); + + spllo(); + + print("Sun Sparc %s\n", sparam->name); + print("bank 0: %ldM 1: %ldM\n", bank[0], bank[1]); + print("frame buffer id %lux slot %ld %s\n",conf.monitor,fbslot,fbstr); + + + if(waserror()) + panic("init0"); + + /* + * These are o.k. because rootinit is null. + * Then early kproc's will have a root and dot. + */ + o = up->env; + o->pgrp->slash = namec("#/", Atodir, 0, 0); + cnameclose(o->pgrp->slash->name); + o->pgrp->slash->name = newcname("/"); + o->pgrp->dot = cclone(o->pgrp->slash); + + chandevinit(); + poperror(); + disinit("/osinit.dis"); +} + + +void +userinit(void) +{ + Proc *p; + Osenv *o; + + p = newproc(); + o = p->env; + + o->fgrp = newfgrp(nil); + o->pgrp = newpgrp(); + kstrdup(&o->user, eve); + strcpy(p->text,"interp"); + + p->fpstate = FPINIT; + fpinit(); + + /* + * Kernel Stack + */ + p->sched.pc = (ulong)init0; + p->sched.sp = (ulong)p->kstack+KSTACK-8; + p->sched.sp &= ~7; /* SP must be 8-byte aligned */ + + ready(p); +} + +uchar * +pusharg(char *p) +{ + int n; + + n = strlen(p)+1; + sp -= n; + memmove(sp, p, n); + return sp; +} + +void +exit(int ispanic) +{ + USED(ispanic); + + spllo(); + print("cpu exiting\n"); + + /* Shutdown running devices */ + chandevshutdown(); + + microdelay(500); + systemreset(); +} + +void +reboot(void) +{ + exit(0); +} + +void +halt(void) +{ + spllo(); + print("cpu halted\n"); + microdelay(500); + for(;;); +} + +int +probemem(ulong addr) +{ + ulong pcr, save0; + int works; + + save0 = getphys(0); + pcr = getpcr()|NOFAULT; + works = 0; + setpcr(pcr & ~MEMPCHECK); + putphys(addr, ~addr); + if(addr) + putphys(0, 0x89ABCDEF); + if(getphys(addr) == ~addr){ + setpcr(pcr); + putphys(addr, addr); + if(addr) + putphys(0, 0x89ABCDEF); + if(getphys(addr) == addr) + works = 1; + } + setpcr(pcr & ~NOFAULT); + putphys(0, save0); + getphys(AFSR); /* clear fault status */ + getrmmu(SFSR); /* clear fault status */ + return works; +} + +/* + * this assumes that if a bank is not empty, + * its first slot is filled. + * + * ../port/alloc.c and ../port/page.c + * need to be changed to support more than two banks. + */ +void +scanbank(ulong base, uchar *mempres, int n) +{ + int i; + ulong addr, npg; + + npg = 0; + for(i=0; i<n; i++){ + mempres[i] = 0; + addr = base + i*MB; + if(!probemem(addr)) + break; + if(addr != base) { + /* check for mirrors */ + putphys(addr, addr); + if(getphys(base) == addr) + break; + } + mempres[i] = 1; + npg += MB/BY2PG; + } + if(npg){ + if(conf.npage0 == 0){ + conf.base0 = base; + conf.npage0 = npg; + }else if(conf.npage1 < npg){ + conf.base1 = base; + conf.npage1 = npg; + } + } +} + +void +physcopyin(void *d, ulong s, int n) +{ + int i, j; + ulong w; + + for(i=0; i<n; i+=sizeof(ulong)) { + w = getphys(s+i); + j = n-i; + if(j > sizeof(ulong)) + j = sizeof(ulong); + memmove((uchar*)d+i, &w, j); + } +} + +Conf conf; + +void +confinit(void) +{ + ulong i; + ulong ktop; + + conf.monitor = 0; + + conf.nmach = 1; + if(conf.nmach > MAXMACH) + panic("confinit"); + + /* fetch ID prom */ + physcopyin(&idprom, NVR_PHYS+IDOFF, sizeof(idprom)); + if(idprom.format!=1 || (idprom.type&0xF0)!=0x80) + *(ulong*)~0 = 0; /* not a new generation sparc; die! */ + + for(sparam = sysparam; sparam->id; sparam++) + if(sparam->id == idprom.type) + break; + + /* First entry in the table is the default */ + if(sparam->id == 0) + sparam = sysparam; + + conf.ss2 = sparam->ss2; + conf.vacsize = sparam->vacsize; + conf.vaclinesize = sparam->vacline; + conf.ncontext = sparam->ncontext; + conf.ss2cachebug = sparam->cachebug; + + for(i=0; i<sparam->nbank; i++) + if(probemem(i*sparam->banksize*MB)) + scanbank(i*sparam->banksize*MB, mempres, + sparam->banksize); + + bank[0] = conf.npage0*BY2PG/MB; + bank[1] = conf.npage1*BY2PG/MB; + + if(bank[1] == 0){ + /* + * This split of memory into 2 banks fools the allocator into + * allocating low memory pages from bank 0 for the ethernet + * since it has only a 24bit address *counter. + * NB. Suns must have at LEAST 8Mbytes. + */ + conf.npage1 = conf.npage0 - (8*MB)/BY2PG; + conf.base1 = conf.base0 + 8*MB; + conf.npage0 = (8*MB)/BY2PG; + bank[1] = bank[0]-8; + bank[0] = 8; + } + + conf.npage = conf.npage0+conf.npage1; + + ktop = PGROUND((ulong)end); + ktop = PADDR(ktop); + conf.npage0 -= ktop/BY2PG; + conf.base0 += ktop; + + conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5; + conf.copymode = 0; /* copy on write */ + conf.arp = 32; + conf.ialloc = (((conf.npage*(100-sparam->pcnt))/100)/2)*BY2PG; + + eve = strdup("inferno"); + +#ifdef notdef + /* XXX - Eric - Autoconfigure memory */ + /* XXX - Tad: 8 eigths, total... */ + mainmem->maxsize = (conf.npage*BY2PG)/8; + heapmem->maxsize = ((conf.npage*BY2PG)*5)/8; + imagmem->maxsize = ((conf.npage*BY2PG)*2)/8; +#endif +} + +/* + * set up the lance + */ +void +lancesetup(Lance *lp) +{ + KMap *k; + DMAdev *dma; + ulong pa, va; + int i; + + k = kmappa(ETHER, PTEIO|PTENOCACHE); + lp->rdp = (void*)(VA(k)+0); + lp->rap = (void*)(VA(k)+2); + for(i=0; i<6; i++) + lp->ea[i] = idprom.ea[i]; + + lp->lognrrb = 7; + lp->logntrb = 7; + lp->nrrb = 1<<lp->lognrrb; + lp->ntrb = 1<<lp->logntrb; + lp->sep = 1; + lp->busctl = BSWP | ACON | BCON; + + /* + * Allocate area for lance init block and descriptor rings + */ + pa = PADDR(xspanalloc(BY2PG, BY2PG, 0)); + + /* map at LANCESEGM */ + va = kmapdma(pa, BY2PG); + lp->lanceram = (ushort*)va; + lp->lm = (Lancemem*)va; + + /* + * Allocate space in host memory for the io buffers. + */ + i = (lp->nrrb+lp->ntrb)*sizeof(Lancepkt); + i = (i+(BY2PG-1))/BY2PG; + pa = PADDR(xspanalloc(i*BY2PG, BY2PG, 0)); + va = kmapdma(pa, i*BY2PG); + + lp->lrp = (Lancepkt*)va; + lp->rp = (Lancepkt*)va; + lp->ltp = lp->lrp+lp->nrrb; + lp->tp = lp->rp+lp->nrrb; + + k = kmappa(DMA, PTEIO|PTENOCACHE); + dma = (DMAdev*)VA(k); + dma->base = 0xff; + + /* + * for now, let's assume the ROM has left the results of its + * auto-sensing + */ +#ifdef notdef + if(dma->ecsr & E_TP_select) + print("Twisted pair ethernet\n"); + else + print("AUI ethernet\n"); +#endif + microdelay(1); + dma->ecsr |= E_Int_en|E_Invalidate|E_Dsbl_wr_inval|E_Dsbl_rd_drn; + microdelay(1); +} + +static void +linkproc(void) +{ + spllo(); + (*up->kpfun)(up->arg); +} + +void +kprocchild(Proc *p, void (*func)(void*), void *arg) +{ + p->sched.pc = (ulong)linkproc; + p->sched.sp = (ulong)p->kstack+KSTACK-8; + + p->kpfun = func; + p->arg = arg; +} + + +void +FPsave(void *f) /* f should be a FPenv */ +{ + savefsr(f); +} + +void +FPrestore(void *f) /* f should be a FPenv */ +{ + restfsr(f); +} + +void +fpsave(FPU *f) +{ + savefpregs( f ); +} + +void +fprestore(FPU *f) +{ + restfpregs(f); +} + +int +islo(void) +{ + int val; + val = (getpsr()&SPL(15)) == 0; + + return val; +} + +void +setvec(void) +{ + /* XXX - Tad: eventually implement this */ +} diff --git a/os/js/mem.h b/os/js/mem.h new file mode 100644 index 00000000..f17c1782 --- /dev/null +++ b/os/js/mem.h @@ -0,0 +1,149 @@ +/* + * Memory and machine-specific definitions. Used in C and assembler. + */ + +/* + * Sizes + */ + +#define BI2BY 8 /* bits per byte */ +#define BI2WD 32 /* bits per word */ +#define BY2WD 4 /* bytes per word */ +#define BY2V 8 /* bytes per double word */ +#define BY2PG 4096 /* bytes per page */ +#define WD2PG (BY2PG/BY2WD) /* words per page */ +#define PGSHIFT 12 /* log(BY2PG) */ +#define ROUND(s, sz) (((s)+(sz-1))&~(sz-1)) +#define PGROUND(s) ROUND(s,BY2PG) + +#define MAXMACH 1 /* max # cpus system can run */ + +/* + * Time + */ +#define HZ 50 /* clock frequency */ +#define MS2HZ (1000/HZ) /* millisec per clock tick */ +#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */ +#define MS2TK(t) ((((ulong)(t))*HZ)/1000) /* milliseconds to ticks */ + +/* + * PSR bits + */ +#define PSREC 0x00002000 +#define PSREF 0x00001000 +#define PSRSUPER 0x00000080 +#define PSRPSUPER 0x00000040 +#define PSRET 0x00000020 +#define SPL(n) (n<<8) + +/* + * Magic registers + */ + +#define MACH 6 /* R6 is m-> */ +#define USER 5 /* R5 is u-> */ + +/* + * Fundamental addresses + */ + +#define USERADDR 0xE0000000 +#define UREGADDR (USERADDR+BY2PG-((32+6)*BY2WD)) +#define BOOTSTACK (KTZERO-0*BY2PG) +#define TRAPS (KTZERO-2*BY2PG) + +/* + * Reference MMU registers (ASI 4) + */ +#define PCR 0x000 +#define CTPR 0x100 +#define CXR 0x200 +#define SFSR 0x300 +#define SFAR 0x400 + +/* + * Processor Control Register + */ +#define ITBRDISABLE (1<<16) +#define BOOTMODE (1<<14) /* `must be cleared for normal operation' */ +#define MEMPCHECK (1<<12) /* check parity */ +#define ENABCACHE (3<<8) /* I & D caches */ +#define NOFAULT (1<<1) /* no fault */ + +/* + * special MMU regions + * DMA segment for SBus DMA mapping via I/O MMU (hardware fixes location) + * the frame buffer is mapped as one MMU region (16 Mbytes) + * IO segments for device register pages etc. + */ +#define DMARANGE 0 +#define DMASEGSIZE ((16*MB)<<DMARANGE) +#define DMASEGBASE (0 - DMASEGSIZE) +#define FBSEGSIZE (1*(16*MB)) /* multiples of 16*MB */ +#define FBSEGBASE (DMASEGBASE - DMASEGSIZE) +#define IOSEGSIZE (16*MB) +#define IOSEGBASE (FBSEGBASE - IOSEGSIZE) + +/* + * MMU entries + */ +#define PTPVALID 1 /* page table pointer */ +#define PTEVALID 2 /* page table entry */ +#define PTERONLY (2<<2) /* read/execute */ +#define PTEWRITE (3<<2) /* read/write/execute */ +#define PTEKERNEL (4<<2) /* execute only */ +#define PTENOCACHE (0<<7) +#define PTECACHE (1<<7) +#define PTEACCESS (1<<5) +#define PTEMODIFY (1<<6) +#define PTEMAINMEM 0 +#define PTEIO 0 +#define PTEPROBEMEM (PTEVALID|PTEKERNEL|PTENOCACHE|PTEWRITE|PTEMAINMEM) +#define PTEUNCACHED PTEACCESS /* use as software flag for putmmu */ + +#define NTLBPID 64 /* limited by microsparc hardware contexts */ + +#define PTEMAPMEM (1024*1024) +#define PTEPERTAB (PTEMAPMEM/BY2PG) +#define SEGMAPSIZE 128 + +#define INVALIDPTE 0 +#define PPN(pa) (((ulong)(pa)>>4)&0x7FFFFF0) +#define PPT(pn) ((ulong*)KADDR((((ulong)(pn)&~0xF)<<4))) + +/* + * Virtual addresses + */ +#define VTAG(va) ((va>>22)&0x03F) +#define VPN(va) ((va>>13)&0x1FF) + +/* + * Address spaces + */ +#define KZERO 0xE0000000 /* base of kernel address space */ +#define KTZERO (KZERO+4*BY2PG) /* first address in kernel text */ +#define KSTACK 8192 /* size of kernel stack */ + +#define MACHSIZE 4096 + +/* + * control registers in physical address space (ASI 20) + */ +#define IOCR 0x10000000 /* IO MMU control register */ +#define IBAR 0x10000004 /* IO MMU page table base address */ +#define AFR 0x10000018 /* address flush register */ +#define AFSR 0x10001000 /* asynch fault status */ +#define AFAR 0x10001004 /* asynch fault address */ +#define SSCR(i) (0x10001010+(i)*4) /* Sbus slot i config register */ +#define MFSR 0x10001020 /* memory fault status register */ +#define MFAR 0x10001024 /* memory fault address register */ +#define MID 0x10002000 /* sbus arbitration enable */ + +#define SYSCTL 0x71F00000 /* system control & reset register */ +#define PROCINTCLR 0x71E00004 /* clear pending processor interrupts */ + +/* + * IO MMU page table entry + */ +#define IOPTEVALID (1<<1) +#define IOPTEWRITE (1<<2) diff --git a/os/js/mkfile b/os/js/mkfile new file mode 100644 index 00000000..1640eb9e --- /dev/null +++ b/os/js/mkfile @@ -0,0 +1,77 @@ +SYSTARG=Inferno +OBJTYPE=sparc +<../../mkconfig + +#Configurable parameters + +CONF=js #default configuration +CONFLIST=js + +SYSTARG=$OSTARG +OBJTYPE=sparc +INSTALLDIR=$ROOT/Inferno/$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, $ETHERS, $VGAS, $PORT, $MISC, $LIBS, $OTHERS + +OBJ=\ + l.$O\ + clock.$O\ + main.$O\ + mmu.$O\ + fsv.$O\ + screen.$O\ + trap.$O\ + rom.$O\ + iob.$O\ + superio.$O\ + kbd.$O\ + $CONF.root.$O\ + $IP\ + $DEVS\ + $ETHERS\ + $LINKS\ + $VGAS\ + $PORT\ + $MISC\ + $OTHERS\ + +LIBNAMES=${LIBS:%=lib%.a} +#LIBDIRS=$LIBS + +HFILES=\ + mem.h\ + dat.h\ + fns.h\ + io.h\ + audio.h\ + cs4231.h\ + ns16552.h\ + rom.h\ + screen.h\ + softcursor.h\ + ureg.h\ + +CFLAGS=-wFV -I$ROOT/Inferno/$OBJTYPE/include -I$ROOT/include -I$ROOT/libinterp +KERNDATE=`{$NDATE} + +default:V: i$CONF + +i$CONF: $OBJ $CONF.c $CONF.root.h $LIBNAMES + $CC $CFLAGS '-DKERNDATE='$KERNDATE $CONF.c + $LD -M -o $target -H3 -T0xE0004000 -R0x4 -l $OBJ $CONF.$O $LIBFILES + +# "raw" version of kernel for binary comparison testing +i$CONF.raw: $OBJ $CONF.c $CONF.root.h $LIBNAMES + $CC $CFLAGS '-DKERNDATE='0 $CONF.c + $LD -s -M -o $target -H3 -T0xE0004000 -R0x4 -l $OBJ $CONF.$O $LIBFILES + +install:V: $INSTALLDIR/i$CONF $INSTALLDIR/i$CONF.raw + +<../port/portmkfile + +%.$O: io.h +clock.$O main.$O trap.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h diff --git a/os/js/mmu.c b/os/js/mmu.c new file mode 100644 index 00000000..4283fa79 --- /dev/null +++ b/os/js/mmu.c @@ -0,0 +1,252 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +typedef struct Ctx Ctx; +/* + * software description of an MMU context + */ +struct Ctx +{ + Ctx *prev; /* less recently used */ + Ctx *next; /* more recently used */ + Proc *proc; /* process that owns this context */ + ushort index; /* which context this is */ +}; + +ulong *ioptes; /* IO MMU's table (shared by all processors) */ + +/* offset of x into the three page table levels in a context */ +#define AOFF(x) (((ulong)x)>>24) +#define BOFF(x) ((((ulong)x)>>18)&(64-1)) +#define COFF(x) ((((ulong)x)>>12)&(64-1)) +#define ISPTAB(x) ((((ulong)x)&3) == PTPVALID) +#define KPN(va) PPN(PADDR(va)) + +#define NIOPTE (DMASEGSIZE/BY2PG) + +/* + * allocate kernel page map and enter one mapping. Return + * address of the mapping. + */ +static ulong* +putkmmu(ulong virt, ulong phys, int level) +{ + ulong *a, *b, *c; + + + a = &PPT(m->contexts[0])[AOFF(virt)]; + if(level > 1) { + if(*a == 0){ + b = (ulong*)xspanalloc(64*sizeof(ulong), + 64*sizeof(ulong), 0); + *a = KPN(b) | PTPVALID; + } else { + if(!ISPTAB(*a)) + panic("putkmmu virt=%lux *a=%lux", virt, *a); + b = PPT(*a); + } + b = &b[BOFF(virt)]; + if(level > 2) { + if(*b == 0){ + c = (ulong*)xspanalloc(64*sizeof(ulong), + 64*sizeof(ulong), 0); + *b = KPN(c) | PTPVALID; + } else { + if(!ISPTAB(*b)) + panic("putkmmu virt=%lux *b=%lux", + virt, *b); + c = PPT(*b); + } + c = &c[COFF(virt)]; + *c = phys; + return c; + } else { + *b = phys; + return b; + } + } else { + *a = phys; + return a; + } +} + +void +mmuinit(void) +{ + int i, n; + ulong *a; + + m->contexts = (ulong*)xspanalloc(conf.ncontext*sizeof(ulong), + conf.ncontext*sizeof(ulong), + 0); + + /* + * context 0 will have the prototype level 1 entries + */ + a = (ulong*)xspanalloc(256*sizeof(ulong), 256*sizeof(ulong), 0); + + m->contexts[0] = KPN(a) | PTPVALID; + + /* + * map all memory to KZERO + */ + n = 128*MB/BY2PG; + + /* pages to first segment boundary */ + for(i=0; i<(256*1024/BY2PG); i++) + putkmmu(KZERO|(i*BY2PG), + PPN(i*BY2PG)|PTEKERNEL|PTEWRITE|PTEVALID|PTECACHE, 3); + + /* segments to first 16Mb boundary */ + for(; i<(16*MB)/BY2PG; i += 64) + putkmmu(KZERO|(i*BY2PG), + PPN(i*BY2PG)|PTEKERNEL|PTEWRITE|PTEVALID|PTECACHE, 2); + + /* 16 Mbyte regions to end */ + for(; i<n; i += 64*64) + putkmmu(KZERO|(i*BY2PG), + PPN(i*BY2PG)|PTEKERNEL|PTEWRITE|PTEVALID|PTECACHE, 1); + + /* + * allocate page table pages for IO mapping + */ + n = IOSEGSIZE/BY2PG; + for(i=0; i<n; i++) + putkmmu(IOSEGBASE+(i*BY2PG), 0, 3); + + /* + * load kernel context + */ + + putrmmu(CTPR, PADDR(m->contexts)>>4); + putrmmu(CXR, 0); + flushtlb(); + + ioptes = (ulong*)xspanalloc(NIOPTE*sizeof(ulong), DMASEGSIZE/1024, 0); + putphys(IBAR, PADDR(ioptes)>>4); + putphys(IOCR, (DMARANGE<<2)|1); /* IO MMU enable */ +} + + +void +flushicache(void) +{ + int i; + ulong addr = 0; + + for(i=0;i<512;i++) { + flushiline(addr); + addr += 1<<5; + } +} + +void +flushdcache(void) +{ + int i; + ulong addr = 0; + + for(i=0;i<512;i++) { + flushdline(addr); + addr += 1<<5; + } +} + +int +segflush(void *p, ulong l) +{ + USED(p,l); + flushicache(); + return 0; +} + +void +cacheinit(void) +{ + flushdcache(); + flushicache(); + setpcr(getpcr()|ENABCACHE); +} + +typedef struct Mregion Mregion; +struct Mregion +{ + ulong addr; + long size; +}; + +struct +{ + Mregion io; + Mregion dma; + Lock; +}kmapalloc = { + {IOSEGBASE, IOSEGSIZE}, + {DMASEGBASE, DMASEGSIZE}, +}; + +void +kmapinit(void) +{ +} + +KMap* +kmappa(ulong pa, ulong flag) +{ + ulong k; + + lock(&kmapalloc); + k = kmapalloc.io.addr; + kmapalloc.io.addr += BY2PG; + if((kmapalloc.io.size -= BY2PG) < 0) + panic("kmappa"); + putkmmu(k, PPN(pa)|PTEKERNEL|PTEWRITE|PTEVALID|flag, 3); + flushtlbpage(k); + unlock(&kmapalloc); + return (KMap*)k; +} + +ulong +kmapdma(ulong pa, ulong n) +{ + ulong va0, va; + int i, j; + + + lock(&kmapalloc); + i = (n+(BY2PG-1))/BY2PG; + va0 = kmapalloc.dma.addr; + kmapalloc.dma.addr += i*BY2PG; + if((kmapalloc.dma.size -= i*BY2PG) <= 0) + panic("kmapdma"); + va = va0; + for(j=0; j<i; j++) { + putkmmu(va, PPN(pa)|PTEKERNEL|PTEVALID|PTEWRITE, 3); + flushtlbpage(va); + ioptes[(va>>PGSHIFT)&(NIOPTE-1)] = PPN(pa)|IOPTEVALID|IOPTEWRITE; + va += BY2PG; + pa += BY2PG; + } + unlock(&kmapalloc); + return va0; +} + +/* + * map the frame buffer + */ +ulong +kmapsbus(int slot) +{ + int i, n; + + lock(&kmapalloc); + n = FBSEGSIZE/BY2PG; + for(i=0; i<n; i += 64*64) + putkmmu(FBSEGBASE+(i*BY2PG), PPN(SBUS(slot)+(i*BY2PG))|PTEKERNEL|PTEWRITE|PTEVALID, 1); + unlock(&kmapalloc); + return FBSEGBASE; +} diff --git a/os/js/ns16552.h b/os/js/ns16552.h new file mode 100644 index 00000000..d36e0c4a --- /dev/null +++ b/os/js/ns16552.h @@ -0,0 +1,81 @@ +/* + * Javastation specific code for the ns16552 (really the superio chip, + * but it has a serial port that looks like the ns16552). + */ +enum +{ + UartFREQ= 1843200, + TTYABase = 0x2F8 +}; + +#define uartwrreg(u,r,v) outb((u)->port + r, (u)->sticky[r] | (v)) +#define uartrdreg(u,r) inb((u)->port + r) + +void ns16552setup(ulong, ulong, char*); + +static void +uartpower(int, int) +{ +} + +/* + * handle an interrupt to a single uart + */ +static void +ns16552intrx(Ureg *ur, void *arg) +{ + USED(ur); + + ns16552intr((ulong)arg); +} + +/* + * install the uarts (called by reset) + */ +void +ns16552install(void) +{ + static int already; + void uartclock(void); + + if(already) + return; + already = 1; + + /* first two ports are always there and always the normal frequency */ + ns16552setup(superiova()+TTYABase, UartFREQ, "eia0"); + ns16552special(0, 38400, &kbdq, &printq, kbdputc); + addclock0link(uartclock, 22); +} + +/* + * If the UART's receiver can be connected to a DMA channel, + * this function does what is necessary to create the + * connection and returns the DMA channel number. + * If the UART's receiver cannot be connected to a DMA channel, + * a -1 is returned. + */ +char +ns16552dmarcv(int dev) +{ + + USED(dev); + return -1; +} + +long +dmasetup(int,void*,long,int) +{ + return 0; +} + +void +dmaend(int) +{ +} + +int +dmacount(int) +{ + return 0; +} diff --git a/os/js/rom.c b/os/js/rom.c new file mode 100644 index 00000000..a477cfe5 --- /dev/null +++ b/os/js/rom.c @@ -0,0 +1,103 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +typedef struct Rom Rom; + +struct Rom +{ + uint magic; + uint version; + uint plugin_version; + uint monitor_id; + + void **physmemlist; + void **virtmemlist; + void **availphysmemlist; + void *config_info; + + char **bootcmd; + + uint (*open)(); + uint (*close)(); + + uint (*read_blocks)(); + uint (*write_blocks)(); + + uint (*transmit_pkt)(); + uint (*poll_pkt)(); + + uint (*read_bytes)(); + uint (*write_bytes)(); + uint (*seek)(); + + uchar *input; + uchar *output; + + uchar (*getchar)(); + uchar (*putchar)(); + uchar (*noblock_getchar)(); + uchar (*noblock_putchar)(); + + uchar (*fb_writestr)(char*); + + void (*boot)(char*); + + void (*printf)(char*,...); + + void (*some_kbd_thing)(); + int *ms_count; + void (*exit)(); + void (**vector)(); + void (**interpret)(char*,...); + void *bootparam; + uint (*mac_addr)(); + char **v2_bootpath; + char ** v2_bootargs; + int *v2_stdin; + int *v2_stdout; + void* (*v2_phandle)(); + char* (*v2_allocphys)(); + char* (*v2_freephys)(); + char* (*v2_map_dev)(); + char* (*v2_unmap_dev)(); + ulong (*v2_open)(); + uint (*v2_close)(); + uint (*v2_read)(); + uint (*v2_write)(); + uint (*v2_seek)(); + void (*v2_chain)(); + void (*v2_release)(); + char *(*v3_alloc)(); + int *reserved[14]; + void (*setctxsegmap)(); + int (*v3_startcpu)(); + int (*v3_stopcpu)(); + int (*v3_idlecpu)(); + int (*v3_resumecpu)(); +}; + +Rom *rom; /* open boot rom vector -- assigned by l.s */ + +void +prom_printf(char *format, ...) +{ + char buf[512]; + int l; + va_list ap; + + va_start(ap, format); + l = vseprint(buf,buf+sizeof(buf),format,ap) - buf; + va_end(ap); + + call_openboot(rom->v2_write,*rom->v2_stdout,buf,l); +} + +void +prom_halt(void) +{ + call_openboot(rom->exit,0xfeedface); +} diff --git a/os/js/rom.h b/os/js/rom.h new file mode 100644 index 00000000..ed4ee2cb --- /dev/null +++ b/os/js/rom.h @@ -0,0 +1,57 @@ +typedef struct ROM ROM; +typedef struct ROMconf ROMconf; + +struct ROM +{ + uint magic; + uint version; + uint plugversion; + uint monid; + uint pad1[3]; + ROMconf *conf; + uint pad2[17]; + void (*boot)(void*); + uint pad3[1]; + void (*enter)(void); + int *msec; + void (*exit)(void); + void (**callback)(void); + uint (*interpret)(void*); + uint pad4[2]; + char **bootpath; + char **bootargs; + uint *stdin; + uint *stdout; + uint (*phandle)(uint); + uint (*alloc)(void*, uint); + void (*free)(void*); + uint (*map)(void*, uint, uint, uint); + void (*unmap)(void*, uint); + uint (*open)(char*); + uint (*close)(uint); + uint (*read)(uint, void*, int); + uint (*write)(uint, void*, int); + uint (*seek)(uint, uint, uint); + void (*chain)(void*, uint, void*, void*, uint); + void (*release)(void*, uint); + uint pad4[15]; + void (*putcxsegm)(int, ulong, int); + int (*startcpu)(uint, uint, uint, uint); + int (*stopcpu)(uint); + int (*idlecpu)(uint); + int (*resumecpu)(uint); +}; + +struct ROMconf +{ + uint (*next)(uint); + uint (*child)(uint); + int (*getproplen)(uint, void*); + int (*getprop)(uint, void*, void*); + int (*setprop)(uint, void*, void*); + void* (*nextprop)(uint, void*); +}; + +#define ROMMAGIC 0x10010407 + +extern ROM *rom; diff --git a/os/js/screen.c b/os/js/screen.c new file mode 100644 index 00000000..17c12376 --- /dev/null +++ b/os/js/screen.c @@ -0,0 +1,483 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "io.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include <draw.h> +#include <memdraw.h> +#include <memlayer.h> +#include <cursor.h> + +#include "softcursor.h" +#include "screen.h" + +#define Backgnd (0xFF) + + +ulong consbits = 0xC0; +Memdata consdata = { + nil, + &consbits +}; +Memimage conscol = +{ + { 0, 0, 1, 1 }, + { -100000, -100000, 100000, 100000 }, + 3, + 1, + &consdata, + 0, + 1 +}; + +ulong onesbits = ~0; +Memdata onesdata = { + nil, + &onesbits, +}; +Memimage xones = +{ + { 0, 0, 1, 1 }, + { -100000, -100000, 100000, 100000 }, + 3, + 1, + &onesdata, + 0, + 1 +}; +Memimage *memones = &xones; + +ulong zerosbits = 0; +Memdata zerosdata = { + nil, + &zerosbits, +}; +Memimage xzeros = +{ + { 0, 0, 1, 1 }, + { -100000, -100000, 100000, 100000 }, + 3, + 1, + &zerosdata, + 0, + 1 +}; +Memimage *memzeros = &xzeros; + +ulong backbits = (Backgnd<<24)|(Backgnd<<16)|(Backgnd<<8)|Backgnd; +Memdata backdata = { + nil, + &backbits +}; +Memimage xback = +{ + { 0, 0, 1, 1 }, + { -100000, -100000, 100000, 100000 }, + 3, + 1, + &backdata, + 0, + 1 +}; +Memimage *back = &xback; + +Video *vid; +static Memsubfont *memdefont; +static Lock screenlock; +Memimage gscreen; +Memdata gscreendata; +static Point curpos; +static Rectangle window; + +static Vctlr* vctlr; + +static Cursor arrow = { + { -1, -1 }, + { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C, + 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, + 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04, + 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40, + }, + { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0, + 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8, + 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8, + 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00, + }, +}; + + +void +graphicscmap(int invert) +{ + int num, den, i, j; + int r, g, b, cr, cg, cb, v; + + if(vctlr->setcolor == nil) + return; + + for(r=0,i=0;r!=4;r++) for(v=0;v!=4;v++,i+=16){ + for(g=0,j=v-r;g!=4;g++) for(b=0;b!=4;b++,j++){ + den=r; + if(g>den) den=g; + if(b>den) den=b; + if(den==0) /* divide check -- pick grey shades */ + cr=cg=cb=v*17; + else{ + num=17*(4*den+v); + cr=r*num/den; + cg=g*num/den; + cb=b*num/den; + } + if(invert) + vctlr->setcolor(255-i-(j&15), + cr*0x01010101, + cg*0x01010101, + cb*0x01010101); + else + vctlr->setcolor(i+(j&15), + cr*0x01010101, + cg*0x01010101, + cb*0x01010101); + } + } +} + +static char s1[] = +{ + 0x00, 0x00, 0xC0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + + +void +dacinit(void) +{ + int i; + + /* Control registers */ + vid->addr = 0x01 << 24; + vid->color = 0x02 << 24; + for(i = 0; i < sizeof s1; i++) + vid->cntrl = s1[i] << 24; + + /* Cursor programming */ + vid->addr = 0x00 << 24; + vid->color = 0x03 << 24; + vid->cntrl = 0xC0 << 24; + for(i = 0; i < 12; i++) + vid->cntrl = 0 << 24; + + /* Load Cursor Ram */ + vid->addr = 0x00 << 24; + vid->color = 0x04 << 24; + for(i = 0; i < 0x400; i++) + vid->cntrl = 0xff << 24; + + graphicscmap(1); + + /* Overlay Palette Ram */ + vid->addr = 0x00 << 24; + vid->color = 0x01 << 24; + for(i = 0; i < 0x10; i++) { + vid->cntrl = 0xff << 24; + vid->cntrl = 0xff << 24; + vid->cntrl = 0xff << 24; + } + + /* Overlay Palette Ram */ + vid->addr = 0x81; + vid->color = 0x01; + for(i = 0; i < 3; i++) { + vid->cntrl = 0xff << 24; + vid->cntrl = 0xff << 24; + vid->cntrl = 0xff << 24; + } +} + +void +vctlrinit(int x, int y, int d) +{ + int h; + ulong va; + + if(vctlr == nil){ + /* + * find a controller somehow + * and call its init routine + */ + extern Vctlr FSV; + + vctlr = FSV.init(0, x, y, d); + vctlr->load(&arrow); + } + + if(vctlr == nil) + panic("%s",Ebadarg); + + gscreen.data = &gscreendata; + gscreen.r.min = Pt(0, 0); + gscreen.r.max = Pt(vctlr->x, vctlr->y); + gscreen.clipr = gscreen.r; + gscreen.ldepth = vctlr->d; + gscreen.repl = 0; + va = kmapsbus(FSVSLOT); /* FSV is in slot 2 */ + gscreendata.data = (ulong *)(va+0x800000); /* Framebuffer Magic */ + gscreen.width = (vctlr->x *(1<<gscreen.ldepth)+31)/32; + + + h = memdefont->height; + + vid = (Video*)(va+0x240000); /* RAMDAC Magic */ + memset(gscreendata.data, Backgnd, vctlr->x*vctlr->y); + window = gscreen.r; + window.max.x = vctlr->x; + window.max.y = (vctlr->y/h) * h; + curpos = window.min; + if (gscreen.ldepth == 3){ + dacinit(); + } + + memset(gscreendata.data, Backgnd, vctlr->x*vctlr->y); + window = gscreen.r; + window.max.x = vctlr->x; + window.max.y = (vctlr->y/h) * h; + curpos = window.min; +} + +void +screeninit(void) +{ + memdefont = getmemdefont(); + vctlrinit(1024, 768, 3); +} + +ulong* +attachscreen(Rectangle *r, int *ld, int *width, int *softscreen) +{ + *r = gscreen.r; + *ld = gscreen.ldepth; + *width = gscreen.width; + *softscreen = 0; + return gscreendata.data; +} + +void +detachscreen(void) +{ +} + +void +flushmemscreen(Rectangle) +{ +} + +static void +scroll(void) +{ + int o; + Point p; + Rectangle r; + + o = 4*memdefont->height; + r = Rpt(window.min, Pt(window.max.x, window.max.y-o)); + p = Pt(window.min.x, window.min.y+o); + memdraw(&gscreen, r, &gscreen, p, memones, p); + r = Rpt(Pt(window.min.x, window.max.y-o), window.max); + memdraw(&gscreen, r, back, memzeros->r.min, memones, memzeros->r.min); + + curpos.y -= o; +} + +void +screenputc(char *buf) +{ + Point p; + int h, w, pos; + Rectangle r; + static int *xp; + static int xbuf[256]; + + h = memdefont->height; + if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)]) + xp = xbuf; + + switch(buf[0]) { + case '\n': + if(curpos.y+h >= window.max.y) + scroll(); + curpos.y += h; + screenputc("\r"); + break; + case '\r': + xp = xbuf; + curpos.x = window.min.x; + break; + case '\t': + p = memsubfontwidth(memdefont, " "); + w = p.x; + *xp++ = curpos.x; + pos = (curpos.x-window.min.x)/w; + pos = 8-(pos%8); + curpos.x += pos*w; + break; + case '\b': + if(xp <= xbuf) + break; + xp--; + r = Rpt(Pt(*xp, curpos.y), Pt(curpos.x, curpos.y + h)); + memdraw(&gscreen, r, back, back->r.min, memones, back->r.min); + curpos.x = *xp; + break; + default: + p = memsubfontwidth(memdefont, buf); + w = p.x; + + if(curpos.x >= window.max.x-w) + screenputc("\n"); + + *xp++ = curpos.x; + memimagestring(&gscreen, curpos, &conscol, memdefont, buf); + curpos.x += w; + } +} + +void +screenputs(char *s, int n) +{ + int i; + Rune r; + char buf[4]; +extern int cold; + +if(!cold) + return; + + if(islo() == 0) { + /* don't deadlock trying to print in interrupt */ + if(!canlock(&screenlock)) + return; + } else + lock(&screenlock); + + while(n > 0) { + i = chartorune(&r, s); + if(i == 0){ + s++; + --n; + continue; + } + memmove(buf, s, i); + buf[i] = 0; + n -= i; + s += i; + screenputc(buf); + } + + unlock(&screenlock); +} + + +void +cursorenable(void) +{ + if(vctlr->enable == nil) + return; + + vctlr->enable(); + + if(!vctlr->isloaded()) + vctlr->load(&arrow); +} + +void +cursordisable(void) +{ + if(vctlr->disable == nil) + return; + + vctlr->disable(); +} + +static Rectangle cursoroffrect; +static int cursorisoff; +static Point hot; + +void +cursorupdate0(void) +{ + int inrect, x, y; + + x = mouse.x - hot.x; + y = mouse.y - hot.y; + inrect = (x >= cursoroffrect.min.x && x < cursoroffrect.max.x + && y >= cursoroffrect.min.y && y < cursoroffrect.max.y); + if (cursorisoff == inrect) + return; + cursorisoff = inrect; + if (inrect) + cursordisable(); + else + cursorenable(); +} + +void +cursorupdate(Rectangle r) +{ + lock(&screenlock); + r.min.x -= 16; + r.min.y -= 16; + cursoroffrect = r; + if (swcursor) + cursorupdate0(); + unlock(&screenlock); +} + +void +drawcursor(Drawcursor* c) +{ + Cursor curs; + int j, i, h, bpl; + uchar *bc, *bs, *cclr, *cset; + + if(vctlr->load == nil) + return; + + /* Set the default system cursor */ + if(c->data == nil) { + lock(&screenlock); + vctlr->load(&arrow); + unlock(&screenlock); + return; + } + + hot.x = c->hotx; + hot.y = c->hoty; + curs.offset = hot; + bpl = bytesperline(Rect(c->minx, c->miny, c->maxx, c->maxy), 0); + + h = (c->maxy-c->miny)/2; + if(h > 16) + h = 16; + + bc = c->data; + bs = c->data + h*bpl; + + cclr = curs.clr; + cset = curs.set; + for(i = 0; i < h; i++) { + for(j = 0; j < 2; j++) { + cclr[j] = bc[j]; + cset[j] = bs[j]; + } + bc += bpl; + bs += bpl; + cclr += 2; + cset += 2; + } + lock(&screenlock); + vctlr->load(&curs); + unlock(&screenlock); +} + diff --git a/os/js/screen.h b/os/js/screen.h new file mode 100644 index 00000000..158ba592 --- /dev/null +++ b/os/js/screen.h @@ -0,0 +1,49 @@ +typedef struct Cursor Cursor; +typedef struct Vctlr Vctlr; +typedef struct Video Video; +typedef struct Thc Thc; + +#define FSVSLOT 2 /* MrCoffee Hard Coded FB Location */ + +struct Cursor +{ + Point offset; + uchar clr[2*16]; + uchar set[2*16]; +}; + +struct Vctlr { + char* name; + Vctlr* (*init)(Vctlr*, int, int, int); + void (*page)(int); + int (*setcolor)(ulong, ulong, ulong, ulong); + + void (*enable)(void); + void (*disable)(void); + void (*move)(int, int); + void (*load)(Cursor*); + int (*isloaded)(void); + int (*cursorintersectsoff)(Rectangle*); + + int x; + int y; + int d; + + Vctlr* link; + + int hidecount; + int loaded; + Cursor cursor; + Lock l; +}; + + +struct Video +{ + /* Brooktree 458/451 */ + ulong addr; /* address register */ + ulong color; /* color palette */ + ulong cntrl; /* control register */ + ulong ovrl; /* overlay palette */ +}; + diff --git a/os/js/softcursor.h b/os/js/softcursor.h new file mode 100644 index 00000000..579914ec --- /dev/null +++ b/os/js/softcursor.h @@ -0,0 +1,13 @@ +/* + * this should be #define'd to nothing if you have a hardware cursor + */ + +void cursormaybeoff(Rectangle*, Memimage*, Rectangle, Memimage*, Point*); + +/* + * also, you should #define cussoron() and cursoroff() to nothing + * if you have a hardware cursor.. This isn't as bad as it sounds, because + * this file is only included in port/devdraw.c, and it doesn't need to + * touch the cursor if it's a hardware cursor + * -Tad + */ diff --git a/os/js/superio.c b/os/js/superio.c new file mode 100644 index 00000000..e3030eab --- /dev/null +++ b/os/js/superio.c @@ -0,0 +1,216 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + + +enum +{ + /* superio configuration registers */ + SioFER = 0x0, /* function enable register */ + SioFAR = 0x1, /* function address register */ + SioPTR = 0x2, /* power and test egister */ + SioFCR = 0x3, /* function control register */ + SioPCR = 0x4, /* printer control register */ + SioKRR = 0x5, /* keyboard and RTC control register */ + SioPMC = 0x6, /* power mgmt control register */ + SioTUP = 0x7, /* tape uart and parallel register */ + SioSID = 0x8, /* SuperIO ID register */ + SioASC = 0x9, /* Advanced SIO Config register */ + SioCS0CF0 = 0xA, /* Chip select 0 config register 0 */ + SioCS0CF1 = 0xB, /* Chip select 0 config register 1 */ + SioCS1CF0 = 0xC, /* Chip select 1 config register 0 */ + SioCS1CF1 = 0xD, /* Chip select 1 config register 1 */ + + /* FER bits */ + PPTEnable = 1<<0, + EnableUART1 = 1<<1, + EnableUART2 = 1<<2, + FDCEnable = 1<<3, + FDC4 = 1<<4, + FDC2ndAddr = 1<<5, + IDEEnable = 1<<6, + IDE2ndAddr = 1<<7, + + /* FAR bits */ + PPTAddr = 3<<0, + UART1Addr = 3<<2, + UART2Addr = 3<<4, + SelectCom3n4 = 3<<6, + + /* PTR bits */ + PWDN = 1<<0, + ClkPWDN = 1<<1, + PWDNSelect = 1<<2, + IRQSelect = 1<<3, + UART1Test = 1<<4, + UART2Test = 1<<5, + LockConfig = 1<<6, + XtndPPTSelect = 1<<7, + + /* FCR bits */ + MediaSense = 1<<0, + DatRateSelect = 1<<0, + IDENTSelect = 1<<1, + PPTFloat = 1<<3, + LogicalDrvXcg = 1<<4, /* logical drive exchange */ + EnaZeroWait = 1<<5, /* zero wait state enable *. + + /* PCR bits */ + EPPEnable = 1<<0, + EPPVersionSel = 1<<1, + ECPEnable = 1<<2, + ECPClkFreeze = 1<<3, + PPTIntPolar = 1<<5, + PPTIntIOCtl = 1<<6, + RTCRamMask = 1<<7, + + /* KRR bits */ + KBCEnable = 1<<0, + KBCSpeedCtl = 1<<1, + EnaProgAccess = 1<<2, + RTCEnable = 1<<3, + RTCClkTst = 1<<4, + RAMSEL = 1<<5, + EnaChipSelect = 1<<6, + KBCClkSource = 1<<7, + + /* PMC bits */ + IDETriStCtl = 1<<0, + FDCTriStCtl = 1<<1, + UARTTriStCtl = 1<<2, + SelectiveLock = 1<<5, + PPTriStEna = 1<<6, + + /* TUP bits */ + EPPToutIntEna = 1<<2, + + /* SID bits are just data values */ + + /* ASC bits */ + IRQ5Select = 1<<0, + DRATE0Select = 1<<0, + DRV2Select = 1<<1, + DR23Select = 1<<1, + EnhancedTDR = 1<<2, + ECPCnfgABit3 = 1<<5, + SystemOpMode0 = 1<<6, + SystemOpMode1 = 1<<7, + + /* CS0CF0 bits are LA0-LA7 */ + /* CS1CF0 bits are LA0-LA7 */ + /* CSxCF1 bits (x=0,1) */ + HA8 = 1<<0, + HA9 = 1<<1, + HA10 = 1<<2, + EnaCSWr = 1<<4, + EnaCSRd = 1<<5, + CSAdrDcode = 1<<6, /* enable full addr decode */ + CSSelectPin = 1<<7, /* CS/CS0 and SYSCLK/CS1 select pin */ +}; + +typedef struct SuperIO SuperIO; + +struct SuperIO +{ + ulong va; + uchar *index; /* superio index register */ + uchar *data; /* superio data register */ + + uchar *mkctl; /* superio mouse/kbd control register */ + uchar *mkdata; /* superio mouse/kbd data register */ +}; + + +static SuperIO sio; + +static void printstatus(uchar status); + +void +superioinit(ulong va, uchar *sindex, uchar *sdata, uchar *mkctl, uchar *mkdata) +{ + sio.va = va; + + sio.index = sindex; + sio.data = sdata; + + sio.mkctl = mkctl; + sio.mkdata = mkdata; +} + + +ulong +superiova(void) +{ + return sio.va; +} + +enum +{ + OBF = 1<<0, + IBF = 1<<1, + SysFlag = 1<<2, + LastWrWasCmd = 1<<3, + KbdEnabled = 1<<4, + FromMouse = 1<<5, + Timeout = 1<<6, + ParityError = 1<<7 +}; + +uchar +superio_readctl(void) +{ + return *sio.mkctl; +} + +uchar +superio_readdata(void) +{ + return *sio.mkdata; +} + +void +superio_writectl(uchar val) +{ + *sio.mkctl = val; +} + +void +superio_writedata(uchar val) +{ + *sio.mkdata = val; +} + + +static void +printstatus(uchar status) +{ + print("0x%2.2ux = <",status); + if(status & OBF) print("OBF|"); + if(status & IBF) print("IBF|"); + if(status & SysFlag) print("SysFlag|"); + if(status & LastWrWasCmd) print("LastWrWasCmd|"); + if(status & KbdEnabled) print("KbdEnabled|"); + if(status & FromMouse) print("FromMouse|"); + if(status & Timeout) print("Timeout|"); + if(status & ParityError) print("ParityErr|"); + print(">"); +} + +void +testit() +{ + uchar status; + uchar val; + + for(;;) { + status = *sio.mkctl; + if(status&OBF) { + printstatus(status); + val = *sio.mkdata; + print(", data = 0x%2.2ux\n",val); + } + } +} diff --git a/os/js/trap.c b/os/js/trap.c new file mode 100644 index 00000000..b9117bfe --- /dev/null +++ b/os/js/trap.c @@ -0,0 +1,472 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "ureg.h" +#include "io.h" +#include "../port/error.h" + +void noted(Ureg**, ulong); +void rfnote(Ureg**); +int domuldiv(ulong, Ureg*); + +extern Label catch; +extern void traplink(void); +extern void syslink(void); +static void faultsparc(Ureg *ur); +static void faultasync(Ureg *ur); + + long ticks; +static char excbuf[64]; /* BUG: not reentrant! */ + +char *trapname[]={ + "reset", + "instruction access exception", + "illegal instruction", + "privileged instruction", + "fp: disabled", + "window overflow", + "window underflow", + "unaligned address", + "fp: exception", + "data access exception", + "tag overflow", + "watchpoint detected", +}; + +char *fptrapname[]={ + "none", + "IEEE 754 exception", + "unfinished FP op", + "unimplemented FP op", + "sequence error", + "hardware error", + "invalid FP register", + "reserved", +} +; + +char* +excname(ulong tbr) +{ + char xx[64]; + char *t; + + switch(tbr){ + case 8: + if(up == 0) + panic("fptrap in kernel\n"); + else{ +panic("fptrap not implemented\n"); +#ifdef notdef + if(m->fpunsafe==0 && up->p->fpstate!=FPactive) + panic("fptrap not active\n"); fsr = up->fpsave.env; + sprint(excbuf, "fp: %s fppc=0x%lux", + fptrapname[(fsr>>14)&7], + up->fpsave.q[0].a, fsr); +#endif + } + return excbuf; + case 36: + return "trap: cp disabled"; + case 37: + return "trap: unimplemented instruction"; + case 40: + return "trap: cp exception"; + case 42: + return "trap: divide by zero"; + case 128: + return "syscall"; + case 129: + return "breakpoint"; + } + t = 0; + if(tbr < sizeof trapname/sizeof(char*)) + t = trapname[tbr]; + if(t == 0){ + if(tbr >= 130) + sprint(xx, "trap instruction %ld", tbr-128); + else if(17<=tbr && tbr<=31) + sprint(xx, "interrupt level %ld", tbr-16); + else + sprint(xx, "unknown trap %ld", tbr); + t = xx; + } + if(strncmp(t, "fp: ", 4) == 0) + strcpy(excbuf, t); + else + sprint(excbuf, "trap: %s", t); + return excbuf; + +} + +void +trap(Ureg *ur) +{ + int user; + ulong tbr, iw; + + tbr = (ur->tbr&0xFFF)>>4; + /* + * Hack to catch bootstrap fault during probe + */ + if(catch.pc) + gotolabel(&catch); + + if(up) + up->dbgreg = ur; + + user = !(ur->psr&PSRPSUPER); + if(user) { + panic("how did we get to user mode???"); + } + if(tbr > 16){ /* interrupt */ + switch(tbr-16) { + case 15: /* asynch mem err */ + faultasync(ur); + break; + case 14: /* processor counter */ + clock(ur); + break; + case 13: /* keyboard/mouse */ + ns16552intr(0); + kbdintr(); + break; + case 6: /* lance */ + lanceintr(); + break; + default: + print("unexp intr lev %ld\n", tbr-16); + goto Error; + } + }else{ + switch(tbr){ + case 1: /* instr. access */ + case 9: /* data access */ + if(up && up->fpstate==FPACTIVE) { + fpquiet(); + fpsave(&up->fpsave); + up->fpstate = FPINACTIVE; + } + faultsparc(ur); + goto Return; + case 2: /* illegal instr, maybe mul */ + iw = *(ulong*)ur->pc; + if((iw&0xC1500000) == 0x80500000){ + if(domuldiv(iw, ur)) + goto Return; + tbr = ur->tbr; + } + break; + case 4: /* floating point disabled */ +panic("some more floating point crapola"); +break; +#ifdef notdef + if(u && u->p){ + if(up->p->fpstate == FPINIT) + restfpregs(initfpp, up->fpsave.fsr); + else if(u->p->fpstate == FPinactive) + restfpregs(&u->fpsave, u->fpsave.fsr); + else + break; + u->p->fpstate = FPactive; + ur->psr |= PSREF; + return; + } + break; +#endif + case 8: /* floating point exception */ +panic("floating point crapola #3"); +break; +#ifdef notdef + /* if unsafe, trap happened shutting down FPU; just return */ + if(m->fpunsafe){ + m->fptrap = (fptrap()==0); + return; + } + if(fptrap()) + goto Return; /* handled the problem */ + break; +#endif + default: + break; + } + Error: + panic("kernel trap: %s pc=0x%lux\n", excname(tbr), ur->pc); + } + Return: + return; +} + +void +trapinit(void) +{ + int i; + long t, a; + + a = ((ulong)traplink-TRAPS)>>2; + a += 0x40000000; /* CALL traplink(SB) */ + t = TRAPS; + for(i=0; i<256; i++){ + *(ulong*)(t+0) = a; /* CALL traplink(SB) */ + *(ulong*)(t+4) = 0xa7480000; /* MOVW PSR, R19 */ + a -= 16/4; + t += 16; + } + +#ifdef notdef + flushpage(TRAPS); +#else + flushicache(); +#endif + + puttbr(TRAPS); + setpsr(getpsr()|PSRET|SPL(15)); /* enable traps, not interrupts */ +} + +void +mulu(ulong u1, ulong u2, ulong *lop, ulong *hip) +{ + ulong lo1, lo2, hi1, hi2, lo, hi, t1, t2, t; + + lo1 = u1 & 0xffff; + lo2 = u2 & 0xffff; + hi1 = u1 >> 16; + hi2 = u2 >> 16; + + lo = lo1 * lo2; + t1 = lo1 * hi2; + t2 = lo2 * hi1; + hi = hi1 * hi2; + t = lo; + lo += t1 << 16; + if(lo < t) + hi++; + t = lo; + lo += t2 << 16; + if(lo < t) + hi++; + hi += (t1 >> 16) + (t2 >> 16); + *lop = lo; + *hip = hi; +} + +void +muls(long l1, long l2, long *lop, long *hip) +{ + ulong t, lo, hi; + ulong mlo, mhi; + int sign; + + sign = 0; + if(l1 < 0){ + sign ^= 1; + l1 = -l1; + } + if(l2 < 0){ + sign ^= 1; + l2 = -l2; + } + mulu(l1, l2, &mlo, &mhi); + lo = mlo; + hi = mhi; + if(sign){ + t = lo = ~lo; + hi = ~hi; + lo++; + if(lo < t) + hi++; + } + *lop = lo; + *hip = hi; +} + +int +domuldiv(ulong iw, Ureg *ur) +{ + long op1, op2; + long *regp; + long *regs; + + regs = (long*)ur; + if(iw & (1<<13)){ /* signed immediate */ + op2 = iw & 0x1FFF; + if(op2 & 0x1000) + op2 |= ~0x1FFF; + }else + op2 = regs[iw&0x1F]; + op1 = regs[(iw>>14)&0x1F]; + regp = ®s[(iw>>25)&0x1F]; + + if(iw & (4<<19)){ /* divide */ + if(ur->y!=0 && ur->y!=~0){ + unimp: + ur->tbr = 37; /* "unimplemented instruction" */ + return 0; /* complex Y is too hard */ + } + if(op2 == 0){ + ur->tbr = 42; /* "zero divide" */ + return 0; + } + if(iw & (1<<19)){ + if(ur->y && (op1&(1<<31))==0) + goto unimp; /* Y not sign extension */ + *regp = op1 / op2; + }else{ + if(ur->y) + goto unimp; + *regp = (ulong)op1 / (ulong)op2; + } + }else{ + if(iw & (1<<19)) + muls(op1, op2, regp, (long*)&ur->y); + else + mulu(op1, op2, (ulong*)regp, &ur->y); + } + if(iw & (16<<19)){ /* set CC */ + ur->psr &= ~(0xF << 20); + if(*regp & (1<<31)) + ur->psr |= 8 << 20; /* N */ + if(*regp == 0) + ur->psr |= 4 << 20; /* Z */ + /* BUG: don't get overflow right on divide */ + } + ur->pc += 4; + ur->npc = ur->pc+4; + return 1; +} + +void +dumpregs(Ureg *ur) +{ + int i; + ulong *l; + + if(up) { + print("registers for %s %ld\n",up->text,up->pid); + if(ur->usp < (ulong)up->kstack || + ur->usp > (ulong)up->kstack+KSTACK-8) + print("invalid stack pointer\n"); + } else + print("registers for kernel\n"); + + print("PSR=%lux PC=%lux TBR=%lux\n", ur->psr, ur->pc, ur->tbr); + l = &ur->r0; + for(i=0; i<32; i+=2, l+=2) + print("R%d\t%.8lux\tR%d\t%.8lux\n", i, l[0], i+1, l[1]); +} + + +/* This routine must save the values of registers the user is not permitted to + * write from devproc and the restore the saved values before returning + */ +void +setregisters(Ureg *xp, char *pureg, char *uva, int n) +{ + ulong psr; + + psr = xp->psr; + memmove(pureg, uva, n); + xp->psr = psr; +} + +void +dumpstack(void) +{ +} + +/* + * Must only be called splhi() when it is safe to spllo(). Because the FP unit + * traps if you touch it when an exception is pending, and because if you + * trap with ET==0 you halt, this routine sets some global flags to enable + * the rest of the system to handle the trap that might occur here without + * upsetting the kernel. Shouldn't be necessary, but safety first. + */ +int +fpquiet(void) +{ + int i, notrap; + ulong fsr; + char buf[128]; + + i = 0; + notrap = 1; + up->fpstate = FPINACTIVE; + for(;;){ + m->fptrap = 0; + fsr = getfsr(); + if(m->fptrap){ + /* trap occurred and up->fpsave contains state */ + sprint(buf, "sys: %s", excname(8)); +#ifdef notdef + postnote(u->p, 1, buf, NDebug); +#else + panic(buf); +#endif + notrap = 0; + break; + } + if((fsr&(1<<13)) == 0) + break; + if(++i > 1000){ + print("fp not quiescent\n"); + break; + } + } + up->fpstate = FPACTIVE; + return notrap; +} + +enum +{ + SE_WRITE = 4<<5, + SE_PROT = 2<<2, +}; + +static void +faultsparc(Ureg *ur) +{ + ulong addr; + char buf[ERRMAX]; + int read; + ulong tbr, ser; + + tbr = (ur->tbr&0xFFF)>>4; + addr = ur->pc; /* assume instr. exception */ + read = 1; + if(tbr == 9){ /* data access exception */ + addr = getrmmu(SFAR); + ser = getrmmu(SFSR); + if(ser&(SE_WRITE)) /* is SE_PROT needed? */ + read = 0; + } + + up->dbgreg = ur; /* for remote acid */ + spllo(); + sprint(buf, "sys: trap: fault %s addr=0x%lux", + read? "read" : "write", addr); + + if(up->type == Interp) + disfault(ur,buf); + dumpregs(ur); + panic("fault: %s", buf); +} + +static void +faultasync(Ureg *ur) +{ + int user; + + print("interrupt 15 AFSR %lux AFAR %lux MFSR %lux MFAR %lux\n", + getphys(AFSR), getphys(AFAR), getphys(MFSR), getphys(MFAR)); + dumpregs(ur); + /* + * Clear interrupt + */ + putphys(PROCINTCLR, 1<<15); + user = !(ur->psr&PSRPSUPER); + if(user) + pexit("Suicide", 0); + panic("interrupt 15"); +} diff --git a/os/js/ureg.h b/os/js/ureg.h new file mode 100644 index 00000000..8433eec9 --- /dev/null +++ b/os/js/ureg.h @@ -0,0 +1,45 @@ +struct Ureg +{ + ulong r0; /* unnecessary; just for symmetry */ + union{ + ulong sp; /* r1 */ + ulong usp; /* r1 */ + ulong r1; + }; + ulong r2; + ulong r3; + ulong r4; + ulong r5; + ulong r6; + ulong r7; + ulong r8; + ulong r9; + ulong r10; + ulong r11; + ulong r12; + ulong r13; + ulong r14; + ulong r15; + ulong r16; + ulong r17; + ulong r18; + ulong r19; + ulong r20; + ulong r21; + ulong r22; + ulong r23; + ulong r24; + ulong r25; + ulong r26; + ulong r27; + ulong r28; + ulong r29; + ulong r30; + ulong r31; + ulong y; + ulong tbr; + ulong psr; + ulong npc; + ulong pc; + ulong pad; /* so structure is double word aligned */ +}; |
