A bitsy/devuart.c => bitsy/devuart.c +506 -0
@@ 0,0 1,506 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+#include "../port/netif.h"
+
+enum
+{
+ Nuart = 1,
+ Stagesize= 1024,
+};
+
+/* hardware registers */
+typedef struct Uartregs Uartregs;
+struct Uartregs
+{
+ ulong ctl0;
+ ulong ctl1;
+ ulong ctl2;
+ ulong ctl3;
+ uchar dummyd[4];
+ ulong data;
+ uchar dummyf[4];
+ ulong status0;
+ ulong status1;
+};
+#define UART3REGS IOA(Uartregs, 0x50000)
+
+/* ctl0 bits */
+enum
+{
+ XmitNotFull = (1 << 2),
+};
+
+/* software representation */
+typedef struct Uart Uart;
+struct Uart
+{
+ QLock;
+ int opens;
+
+ int enabled;
+ Uart *elist; /* next enabled interface */
+ char name[NAMELEN];
+
+ uchar sticky[8]; /* sticky write register values */
+ uchar osticky[8]; /* kernel saved sticky write register values */
+ ulong port; /* io ports */
+ ulong freq; /* clock frequency */
+ uchar mask; /* bits/char */
+ int dev;
+ int baud; /* baud rate */
+
+ uchar istat; /* last istat read */
+ int frame; /* framing errors */
+ int overrun; /* rcvr overruns */
+
+ /* buffers */
+ int (*putc)(Queue*, int);
+ Queue *iq;
+ Queue *oq;
+
+ Lock flock; /* fifo */
+ uchar fifoon; /* fifo's enabled */
+ uchar type; /* chip version */
+
+ Lock rlock; /* receive */
+ uchar istage[Stagesize];
+ uchar *ip;
+ uchar *ie;
+
+ int haveinput;
+
+ Lock tlock; /* transmit */
+ uchar ostage[Stagesize];
+ uchar *op;
+ uchar *oe;
+
+ int modem; /* hardware flow control on */
+ int xonoff; /* software flow control on */
+ int blocked;
+ int cts, dsr, dcd, dcdts; /* keep track of modem status */
+ int ctsbackoff;
+ int hup_dsr, hup_dcd; /* send hangup upstream? */
+ int dohup;
+
+ int kinuse; /* device in use by kernel */
+
+ Rendez r;
+};
+static Uart* uart[Nuart];
+static int nuart;
+
+static Dirtab *uartdir;
+static int uartndir;
+
+/*
+ * means the kernel is using this for debugging output
+ */
+static char Ekinuse[] = "device in use by kernel";
+
+/*
+ * default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts,
+ * transmit and receive enabled, interrupts disabled.
+ */
+static void
+uartsetup0(Uart *p)
+{
+ memset(p->sticky, 0, sizeof(p->sticky));
+ /*
+ * set rate to 9600 baud.
+ * 8 bits/character.
+ * 1 stop bit.
+ * interrupts enabled.
+ */
+// p->sticky[Format] = Bits8;
+// uartwrreg(p, Format, 0);
+// p->sticky[Mctl] |= Inton;
+// uartwrreg(p, Mctl, 0x0);
+
+// uartsetbaud(p, 9600);
+
+// p->iq = qopen(4*1024, 0, uartflow, p);
+// p->oq = qopen(4*1024, 0, uartkick, p);
+ if(p->iq == nil || p->oq == nil)
+ panic("uartsetup0");
+
+ p->ip = p->istage;
+ p->ie = &p->istage[Stagesize];
+ p->op = p->ostage;
+ p->oe = p->ostage;
+}
+
+/*
+ * called by main() to create a new duart
+ */
+void
+uartsetup(ulong port, ulong freq, char *name, int type)
+{
+ Uart *p;
+
+ if(nuart >= Nuart)
+ return;
+
+ p = xalloc(sizeof(Uart));
+ uart[nuart] = p;
+ strcpy(p->name, name);
+ p->dev = nuart;
+ nuart++;
+ p->port = port;
+ p->freq = freq;
+ p->type = type;
+ uartsetup0(p);
+}
+
+static void
+uartenable(Uart *p)
+{
+ USED(p);
+}
+
+static void
+uartdisable(Uart *p)
+{
+ USED(p);
+}
+
+static long
+uartstatus(Chan*, Uart *p, void *buf, long n, long offset)
+{
+ USED(p);
+// "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
+// "dev(%d) type(%d) framing(%d) overruns(%d)%s%s%s%s\n",
+ return readstr(offset, buf, n, "");
+}
+
+static void
+setlength(int i)
+{
+ Uart *p;
+
+ if(i > 0){
+ p = uart[i];
+ if(p && p->opens && p->iq)
+ uartdir[3*i].length = qlen(p->iq);
+ } else for(i = 0; i < nuart; i++){
+ p = uart[i];
+ if(p && p->opens && p->iq)
+ uartdir[3*i].length = qlen(p->iq);
+ }
+}
+
+static void
+uartreset(void)
+{
+ int i;
+ Dirtab *dp;
+
+ nuart = Nuart;
+
+ uartndir = 3*nuart;
+ uartdir = xalloc(uartndir * sizeof(Dirtab));
+ dp = uartdir;
+ for(i = 0; i < nuart; i++){
+ /* 3 directory entries per port */
+ sprint(dp->name, "eia%d", i);
+ dp->qid.path = NETQID(i, Ndataqid);
+ dp->perm = 0660;
+ dp++;
+ sprint(dp->name, "eia%dctl", i);
+ dp->qid.path = NETQID(i, Nctlqid);
+ dp->perm = 0660;
+ dp++;
+ sprint(dp->name, "eia%dstat", i);
+ dp->qid.path = NETQID(i, Nstatqid);
+ dp->perm = 0444;
+ dp++;
+ }
+
+}
+
+
+static Chan*
+uartattach(char *spec)
+{
+ return devattach('t', spec);
+}
+
+static int
+uartwalk(Chan *c, char *name)
+{
+ return devwalk(c, name, uartdir, uartndir, devgen);
+}
+
+static void
+uartstat(Chan *c, char *dp)
+{
+ if(NETTYPE(c->qid.path) == Ndataqid)
+ setlength(NETID(c->qid.path));
+ devstat(c, dp, uartdir, uartndir, devgen);
+}
+
+static Chan*
+uartopen(Chan *c, int omode)
+{
+ Uart *p;
+
+ c = devopen(c, omode, uartdir, uartndir, devgen);
+
+ switch(NETTYPE(c->qid.path)){
+ case Nctlqid:
+ case Ndataqid:
+ p = uart[NETID(c->qid.path)];
+ if(p->kinuse)
+ error(Ekinuse);
+ qlock(p);
+ if(p->opens++ == 0){
+ uartenable(p);
+ qreopen(p->iq);
+ qreopen(p->oq);
+ }
+ qunlock(p);
+ break;
+ }
+
+ return c;
+}
+
+static void
+uartclose(Chan *c)
+{
+ Uart *p;
+
+ if(c->qid.path & CHDIR)
+ return;
+ if((c->flag & COPEN) == 0)
+ return;
+ switch(NETTYPE(c->qid.path)){
+ case Ndataqid:
+ case Nctlqid:
+ p = uart[NETID(c->qid.path)];
+ if(p->kinuse)
+ error(Ekinuse);
+ qlock(p);
+ if(--(p->opens) == 0){
+ uartdisable(p);
+ qclose(p->iq);
+ qclose(p->oq);
+ p->ip = p->istage;
+ p->dcd = p->dsr = p->dohup = 0;
+ }
+ qunlock(p);
+ break;
+ }
+}
+
+static long
+uartread(Chan *c, void *buf, long n, vlong off)
+{
+ Uart *p;
+ ulong offset = off;
+
+ if(c->qid.path & CHDIR){
+ setlength(-1);
+ return devdirread(c, buf, n, uartdir, uartndir, devgen);
+ }
+
+ p = uart[NETID(c->qid.path)];
+ if(p->kinuse)
+ error(Ekinuse);
+ switch(NETTYPE(c->qid.path)){
+ case Ndataqid:
+ return qread(p->iq, buf, n);
+ case Nctlqid:
+ return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
+ case Nstatqid:
+ return uartstatus(c, p, buf, n, offset);
+ }
+
+ return 0;
+}
+
+static void
+uartctl(Uart *p, char *cmd)
+{
+ int i, n;
+ char *f[32];
+ int nf;
+
+ /* let output drain for a while */
+ for(i = 0; i < 16 && qlen(p->oq); i++)
+ tsleep(&p->r, (int(*)(void*))qlen, p->oq, 125);
+
+ nf = getfields(cmd, f, nelem(f), 1, " \t\n");
+
+ for(i = 0; i < nf; i++){
+
+ if(strncmp(f[i], "break", 5) == 0){
+// uartbreak(p, 0);
+ continue;
+ }
+
+ n = atoi(f[i]+1);
+ switch(*f[i]){
+ case 'B':
+ case 'b':
+// uartsetbaud(p, n);
+ break;
+ case 'C':
+ case 'c':
+// uartdcdhup(p, n);
+ break;
+ case 'D':
+ case 'd':
+// uartdtr(p, n);
+ break;
+ case 'E':
+ case 'e':
+// uartdsrhup(p, n);
+ break;
+ case 'f':
+ case 'F':
+ qflush(p->oq);
+ break;
+ case 'H':
+ case 'h':
+ qhangup(p->iq, 0);
+ qhangup(p->oq, 0);
+ break;
+ case 'i':
+ case 'I':
+// lock(&p->flock);
+// uartfifo(p, n);
+// unlock(&p->flock);
+ break;
+ case 'L':
+ case 'l':
+// uartbits(p, n);
+ break;
+ case 'm':
+ case 'M':
+// uartmflow(p, n);
+ break;
+ case 'n':
+ case 'N':
+ qnoblock(p->oq, n);
+ break;
+ case 'P':
+ case 'p':
+// uartparity(p, *(cmd+1));
+ break;
+ case 'K':
+ case 'k':
+// uartbreak(p, n);
+ break;
+ case 'R':
+ case 'r':
+// uartrts(p, n);
+ break;
+ case 'Q':
+ case 'q':
+ qsetlimit(p->iq, n);
+ qsetlimit(p->oq, n);
+ break;
+ case 'T':
+ case 't':
+// uartdcdts(p, n);
+ break;
+ case 'W':
+ case 'w':
+ /* obsolete */
+ break;
+ case 'X':
+ case 'x':
+ ilock(&p->tlock);
+ p->xonoff = n;
+ iunlock(&p->tlock);
+ break;
+ }
+ }
+}
+
+static long
+uartwrite(Chan *c, void *buf, long n, vlong)
+{
+ Uart *p;
+ char cmd[32];
+
+ if(c->qid.path & CHDIR)
+ error(Eperm);
+
+ p = uart[NETID(c->qid.path)];
+ if(p->kinuse)
+ error(Ekinuse);
+
+ switch(NETTYPE(c->qid.path)){
+ case Ndataqid:
+ return qwrite(p->oq, buf, n);
+ case Nctlqid:
+ if(n >= sizeof(cmd))
+ n = sizeof(cmd)-1;
+ memmove(cmd, buf, n);
+ cmd[n] = 0;
+ uartctl(p, cmd);
+ return n;
+ }
+}
+
+static void
+uartwstat(Chan *c, char *dp)
+{
+ Dir d;
+ Dirtab *dt;
+
+ if(!iseve())
+ error(Eperm);
+ if(CHDIR & c->qid.path)
+ error(Eperm);
+ if(NETTYPE(c->qid.path) == Nstatqid)
+ error(Eperm);
+
+ dt = &uartdir[3 * NETID(c->qid.path)];
+ convM2D(dp, &d);
+ d.mode &= 0666;
+ dt[0].perm = dt[1].perm = d.mode;
+}
+
+Dev uartdevtab = {
+ 't',
+ "uart",
+
+ uartreset,
+ devinit,
+ uartattach,
+ devclone,
+ uartwalk,
+ uartstat,
+ uartopen,
+ devcreate,
+ uartclose,
+ uartread,
+ devbread,
+ uartwrite,
+ devbwrite,
+ devremove,
+ uartwstat,
+};
+
+void
+putuartstr(char *str)
+{
+ Uartregs *ur;
+
+ ur = UART3REGS;
+ while(*str){
+ /* wait for output ready */
+ while(ur->status1 & XmitNotFull)
+ ;
+ ur->data = *str++;
+
+ }
+}
M bitsy/fns.h => bitsy/fns.h +1 -0
@@ 15,6 15,7 @@ int iprint(char*, ...);
#define procrestore(p)
void procsave(Proc*);
void procsetup(Proc*);
+void putuartstr(char*);
void screeninit(void);
int screenprint(char*, ...); /* debugging */
void (*screenputs)(char*, int);
M bitsy/io.h => bitsy/io.h +5 -112
@@ 1,112 1,5 @@
-/* replicated in part from the boot code, for now */
-
-#define XTAL 3686400
-#define CORECLOCK 199066000
-#define MONITOR 0x00020000
-
-#define SYS_REGBASE 0x90000000
-
-#define SYSR_FIRQ 0x1000
-#define SYSR_IRQ 0x1400
-#define SIRQ_PCI (1<<2)
-#define SIRQ_UART (1<<8)
-#define SYSR_UART_SR 0x3400 /* UART Status Register */
-#define SYSR_UART_CR 0x3800 /* UART Control Register */
-#define SYSR_UART_DR 0x3C00 /* UART Data Register */
-
-#define SYS_FIRQ (0x90000000+SYSR_FIRQ)
-#define SYS_IRQ (0x90000000+SYSR_IRQ)
-
-#define PCI_REGBASE 0x42000000
-#define PCI_IPXRESET 0x07C
-#define PCI_IRQSTATUS 0x180
-#define PCI_IRQRSTATUS 0x184
-#define PCI_IRQENABLE 0x188
-#define PCI_IRQENA_SET 0x188
-#define PCI_IRQENA_CLR 0x18C
-#define PCI_IRQSOFT 0x190
-#define PCI_FIRQSTATUS 0x280
-#define PCI_FIRQRSTATUS 0x284
-#define PCI_FIRQENABLE 0x288
-#define PCI_FIRQENA_SET 0x288
-#define PCI_FIRQENA_CLR 0x28C
-#define PCI_FIRQSOFT 0x290
-#define PCI_TIMERLOAD 0x300
-#define PCI_TIMERVALUE 0x304
-#define PCI_TIMERCTL 0x308
-#define PCI_TIMERCLEAR 0x30C
-
-#define TIMER_OFF 0x020
-
-#define TIMER1_LOAD (PCI_REGBASE+PCI_TIMERLOAD)
-#define TIMER1_VALUE (PCI_REGBASE+PCI_TIMERVALUE)
-#define TIMER1_CTL (PCI_REGBASE+PCI_TIMERCTL)
-#define TIMER1_CLEAR (PCI_REGBASE+PCI_TIMERCLEAR)
-
-#define TIMER_PERIODIC (1<<6)
-#define TIMER_ENABLE (1<<7)
-
-#define IRQ_STATUS (PCI_REGBASE+PCI_IRQSTATUS)
-#define IRQ_ENABLE_SET (PCI_REGBASE+PCI_IRQENA_SET)
-#define IRQ_ENABLE_CLR (PCI_REGBASE+PCI_IRQENA_CLR)
-
-#define FIRQ_OFF 0x100
-
-#define IRQ_SOFT 1
-#define IRQ_TIMER1 4
-#define IRQ_TIMER2 5
-#define IRQ_TIMER3 6
-#define IRQ_TIMER4 7
-#define IRQ_DOOR 15
-#define IRQ_DMA1 16
-#define IRQ_DMA2 17
-#define IRQ_PCI 18
-#define IRQ_DMA1NB 20
-#define IRQ_DMA2NB 21
-#define IRQ_BIST 22
-#define IRQ_SERR 23
-#define IRQ_I2OIN 25
-#define IRQ_POWER 26
-#define IRQ_DTIMER 27
-#define IRQ_PARITY 28
-#define IRQ_MABORT 29
-#define IRQ_TABORT 30
-#define IRQ_DPARITY 31
-
-#define PCI_CONF1_BASE 0x52000000
-#define PCI_CONF0_BASE 0x53000000
-#define PCI_IO_BASE 0x54000000
-#define PCI_IO_SIZE 0x00010000
-#define PCI_MEM_BASE 0x60000000
-#define PCI_MEM_SIZE 0x20000000
-
-/* MMU. */
-
-#define MMUCR_M_ENABLE (1<<0) /* MMU enable */
-#define MMUCR_A_ENABLE (1<<1) /* Address alignment fault enable */
-#define MMUCR_C_ENABLE (1<<2) /* (data) cache enable */
-#define MMUCR_W_ENABLE (1<<3) /* write buffer enable */
-#define MMUCR_PROG32 (1<<4) /* PROG32 */
-#define MMUCR_DATA32 (1<<5) /* DATA32 */
-#define MMUCR_L_ENABLE (1<<6) /* Late abort on earlier CPUs */
-#define MMUCR_BIGEND (1<<7) /* Big-endian (=1), little-endian (=0) */
-#define MMUCR_SYSTEM (1<<8) /* System bit, modifies MMU protections */
-#define MMUCR_ROM (1<<9) /* ROM bit, modifies MMU protections */
-#define MMUCR_F (1<<10) /* Should Be Zero */
-#define MMUCR_Z_ENABLE (1<<11) /* Branch prediction enable on 810 */
-#define MMUCR_I_ENABLE (1<<12) /* Instruction cache enable on SA110 */
-
-#define SDRAM_BASE 0xC0000000
-#define SDRAM_RESV (16*1024*1024)
-#define SDRAM_SIZE (32*1024*1024)
-
-#define PMEM_BASE (SDRAM_BASE+SDRAM_RESV)
-#define PMEM_TOP (SDRAM_BASE+SDRAM_SIZE)
-#define KTOP (KZERO + (SDRAM_SIZE - SDRAM_RESV))
-
-#define SLOW_BASE 0x38400000
-#define SLEDOFFSET 0x00108000
-
-#define LEDADDR (SLOW_BASE+SLEDOFFSET)
-
-#define SACADDR 0x08100000
+/*
+ * all register offsets are relative to 0x8000000 so that
+ * IOZERO can be changed at some future point
+ */
+#define IOA(t, x) ((t*)(IOZERO|x))
M bitsy/l.s => bitsy/l.s +73 -59
@@ 25,9 25,9 @@ _main:
BL main(SB)
BL exit(SB)
/* we shouldn't get here */
- BL _div(SB) /* hack to get _div etc loaded */
_mainloop:
B _mainloop
+ BL _div(SB) /* hack to get _div etc loaded */
/* flush tlb's */
TEXT flushmmu(SB), $-4
@@ 79,10 79,13 @@ TEXT getfar(SB), $-4
MRC CpMMU, 0, R0, C(CpFAR), C(0x0)
RET
-/* st the translation table base */
+/* set the translation table base */
TEXT setttb(SB), $-4
MCR CpMMU, 0, R0, C(CpTTB), C(0x0)
+/*
+ * set the stack value for the mode passed in R0
+ */
TEXT setr13(SB), $-4
MOVW 4(FP), R1
@@ 97,97 100,108 @@ TEXT setr13(SB), $-4
MOVW R2, CPSR
RET
+/*
+ * exception vectors, copied by trapinit() to somewhere useful
+ */
TEXT vectors(SB), $-4
- MOVW 0x18(R15), R15 /* reset */
- MOVW 0x18(R15), R15 /* undefined */
- MOVW 0x18(R15), R15 /* SWI */
- MOVW 0x18(R15), R15 /* prefetch abort */
- MOVW 0x18(R15), R15 /* data abort */
- MOVW 0x18(R15), R15 /* reserved */
- MOVW 0x18(R15), R15 /* IRQ */
- MOVW 0x18(R15), R15 /* FIQ */
-
-TEXT vtable(SB), $-4
- WORD $_vsvc(SB) /* reset, in svc mode already */
- WORD $_vund(SB) /* undefined, switch to svc mode */
- WORD $_vsvc(SB) /* swi, in svc mode already */
- WORD $_vpab(SB) /* prefetch abort, switch to svc mode */
- WORD $_vdab(SB) /* data abort, switch to svc mode */
- WORD $_vsvc(SB) /* reserved */
- WORD $_virq(SB) /* IRQ, switch to svc mode */
- WORD $_vfiq(SB) /* FIQ, switch to svc mode */
-
-TEXT _vund(SB), $-4 /* undefined */
- MOVM.IA [R0-R3], (R13)
+ MOVW 0x18(R15), R15 /* reset */
+ MOVW 0x18(R15), R15 /* undefined */
+ MOVW 0x18(R15), R15 /* SWI */
+ MOVW 0x18(R15), R15 /* prefetch abort */
+ MOVW 0x18(R15), R15 /* data abort */
+ MOVW 0x18(R15), R15 /* reserved */
+ MOVW 0x18(R15), R15 /* IRQ */
+ MOVW 0x18(R15), R15 /* FIQ */
+ WORD $_vsvc(SB) /* reset, in svc mode already */
+ WORD $_vund(SB) /* undefined, switch to svc mode */
+ WORD $_vsvc(SB) /* swi, in svc mode already */
+ WORD $_vpab(SB) /* prefetch abort, switch to svc mode */
+ WORD $_vdab(SB) /* data abort, switch to svc mode */
+ WORD $_vsvc(SB) /* reserved */
+ WORD $_virq(SB) /* IRQ, switch to svc mode */
+ WORD $_vfiq(SB) /* FIQ, switch to svc mode */
+
+TEXT _vsvc(SB), $-4 /* reset or SWI or reserved */
+ SUB $12, R13 /* make room for pc, psr, & type */
+ MOVW R14, 8(R13) /* ureg->pc = interupted PC */
+ MOVW SPSR, R14 /* ureg->psr = SPSR */
+ MOVW R14, 4(R13) /* ... */
+ MOVW $PsrMsvc, R14 /* ureg->type = PsrMsvc */
+ MOVW R14, (R13) /* ... */
+ MOVM.DB.W.S [R0-R14], (R13) /* save user level registers, at end r13 points to ureg */
+ B _vexcep /* call the exception handler */
+
+TEXT _vund(SB), $-4 /* undefined */
+ MOVM.IA [R0-R3], (R13) /* free some working space */
MOVW $PsrMund, R0
B _vswitch
-TEXT _vsvc(SB), $-4 /* reset or SWI or reserved */
- SUB $12, R13 /* make room for pc, psr, & type */
- MOVW R14, 8(R13) /* ureg->pc = interupted PC */
- MOVW SPSR, R14 /* ureg->psr = SPSR */
- MOVW R14, 4(R13) /* ... */
- MOVW $PsrMsvc, R14 /* ureg->type = PsrMsvc */
- MOVW R14, (R13) /* ... */
- B _vsaveu
-
-TEXT _vpab(SB), $-4 /* prefetch abort */
- MOVM.IA [R0-R3], (R13) /* free some working space */
- MOVW $PsrMabt, R0 /* r0 = type */
+TEXT _vpab(SB), $-4 /* prefetch abort */
+ MOVM.IA [R0-R3], (R13) /* free some working space */
+ MOVW $PsrMabt, R0 /* r0 = type */
B _vswitch
-TEXT _vdab(SB), $-4 /* data abort */
- MOVM.IA [R0-R3], (R13) /* free some working space */
- MOVW $(PsrMabt+1), R0 /* r0 = type */
- B _vswitch /*
-
-TEXT _virq(SB), $-4 /* IRQ */
- MOVM.IA [R0-R3], (R13) /* free some working space */
- MOVW $PsrMirq, R0 /* r0 = type */
+TEXT _vdab(SB), $-4 /* data abort */
+ MOVM.IA [R0-R3], (R13) /* free some working space */
+ MOVW $(PsrMabt+1), R0 /* r0 = type */
B _vswitch
-TEXT _vfiq(SB), $-4 /* FIQ */
- MOVM.IA [R0-R3], (R13) /* free some working space */
- MOVW $PsrMfiq, R0 /* r0 = type */
+TEXT _virq(SB), $-4 /* IRQ */
+ MOVM.IA [R0-R3], (R13) /* free some working space */
+ MOVW $PsrMirq, R0 /* r0 = type */
B _vswitch
+TEXT _vfiq(SB), $-4 /* FIQ */
+ RFE /* RIQ is special, ignore it for now */
+
/*
* come here with type in R0 and R13 pointing above saved [r0-r3]
*/
_vswitch: /* switch to svc, type in R0 */
- MOVW SPSR, R1 /* SPSR for ureg */
- MOVW R14, R2 /* interrupted pc for ureg */
- MOVW R13, R3 /* [R0-R3] save area */
+ MOVW SPSR, R1 /* save SPSR for ureg */
+ MOVW R14, R2 /* save interrupted pc for ureg */
+ MOVW R13, R3 /* save pointer to where the original [R0-R3] are */
- /* switch to svc mode, we get new R13 pointing to top of svc stack */
+ /* switch to svc mode */
MOVW CPSR, R14
BIC $PsrMask, R14
ORR $(PsrDirq|PsrDfiq|PsrMsvc), R14
MOVW R14, CPSR
+ /*
+ * R13 and R14 is now R13_SVC and R14_SVC. The values of the previous mode's
+ * R13 and R14 are no longer accessible. That's why R3 was left to point to where
+ * the old [r0-r3] are stored.
+ */
MOVM.DB.W [R0-R2], (R13) /* set ureg->{pc, psr, type}; r13 points to ureg->type */
MOVM.IA (R3), [R0-R3] /* restore [R0-R3] from previous mode's stack */
- B _vsaveu
+ MOVM.DB.W.S [R0-R14], (R13) /* save user level registers, at end r13 points to ureg */
- /*
- * come here with R13 pointing to ureg->type
+ /*
+ * if the original interrupt happened while executing SVC mode, the User R14 in the Ureg is
+ * wrong. We need to save the SVC one there.
*/
-_vsaveu:
- MOVM.DB.W.S [R0-R14], (R13) /* save user level registers, r13 points to ureg */
-
- MOVW $setR12(SB), R12 /* the SB from user mode is different */
+ MOVW 0x40(R13), R1
+ AND.S $0xf, R1
+ MOVW.NE R14,0x38(R13)
+ B _vexcep
+ /*
+ * call the exception routine, the ureg is at the bottom of the stack
+ */
+_vexcep:
+ MOVW $setR12(SB), R12 /* Make sure we've got the kernel's SB loaded */
MOVW R13, R0 /* first arg is pointer to ureg */
SUB $8, R13 /* space for argument+link */
BL exception(SB)
_vrfe:
- ADD $(8+4*15), R13 /* r13 points to ureg->type */
+ ADD $(8+4*15), R13 /* make r13 point to ureg->type */
MOVW 8(R13), R14 /* restore link */
MOVW 4(R13), R0 /* restore SPSR */
MOVW R0, SPSR /* ... */
MOVM.DB.S (R13), [R0-R14] /* restore registers */
- ADD $8, R13 /* skip saved type+SPSR */
+ ADD $8, R13 /* pop past ureg->{type+psr} */
RFE /* MOVM.IA.S.W (R13), [R15] */
TEXT splhi(SB), $-4
M bitsy/main.c => bitsy/main.c +5 -2
@@ 14,7 14,7 @@ Conf conf;
void
main(void)
{
-
+ putuartstr("hello ken");
}
/*
@@ 23,7 23,10 @@ main(void)
void
exit(int ispanic)
{
- USED(ispanic);
+ void (*f)();
+
+ f = nil;
+ (*f)();
}
/*
M bitsy/mem.h => bitsy/mem.h +15 -2
@@ 33,13 33,26 @@
#define MACHADDR (KZERO+0x00001000)
/*
- * Address spaces
+ * Address spaces:
+ *
+ * We've direct mapped the DRAM's and all the
+ * special use space. Since the DRAM's lie at
+ * 0xc0000000 and since the Compaq boot loader
+ * copies the kernel to the start of DRAM, we've
+ * made KZERO 0xc0000000. We've also direct mapped
+ * the special use io space between 0x8000000 and KZERO.
+ * That means we can leave the MMU off till we're pretty
+ * far into the boot.
+ *
+ * Both these decisions can be changed by putting an MMU setup in
+ * l.s and changing the definitions below.
*/
#define UZERO 0 /* base of user address space */
#define UTZERO (UZERO+BY2PG) /* first address in user text */
#define KZERO 0xC0000000 /* base of kernel address space */
#define KTZERO 0xC0008000 /* first address in kernel text */
-#define USTKTOP (KZERO-BY2PG) /* byte just beyond user stack */
+#define IOZERO 0x80000000 /* 1 gig of special regs */
+#define USTKTOP (IOZERO-BY2PG) /* byte just beyond user stack */
#define USTKSIZE (16*1024*1024) /* size of user stack */
#define TSTKTOP (USTKTOP-USTKSIZE) /* end of new stack in sysexec */
#define TSTKSIZ 100
A pc/vga3dfx.c => pc/vga3dfx.c +78 -0
@@ 0,0 1,78 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+#define Image IMAGE
+#include <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#include "screen.h"
+
+static ulong
+tdfxlinear(VGAscr* scr, int* size, int* align)
+{
+ ulong aperture, oaperture;
+ int oapsize, wasupamem;
+ Pcidev *p;
+
+ oaperture = scr->aperture;
+ oapsize = scr->apsize;
+ wasupamem = scr->isupamem;
+
+ aperture = 0;
+ if(p = pcimatch(nil, 0x121A, 0)){
+ switch(p->did){
+ case 0x0005: /* Voodoo 3 3000 */
+ aperture = p->mem[1].bar & ~0x0F;
+ *size = p->mem[1].size;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if(wasupamem){
+ if(oaperture == aperture)
+ return oaperture;
+ upafree(oaperture, oapsize);
+ }
+ scr->isupamem = 0;
+
+ aperture = upamalloc(aperture, *size, *align);
+ if(aperture == 0){
+ if(wasupamem && upamalloc(oaperture, oapsize, 0)){
+ aperture = oaperture;
+ scr->isupamem = 1;
+ }
+ else
+ scr->isupamem = 0;
+ }
+ else
+ scr->isupamem = 1;
+
+ return aperture;
+}
+
+VGAdev vga3dfxdev = {
+ "3dfx",
+
+ nil, /* enable */
+ nil, /* disable */
+ nil, /* page */
+ tdfxlinear, /* linear */
+ nil, /* drawinit */
+ nil, /* fill */
+};
+
+VGAcur vga3dfxcur = {
+ "3dfxhwgc",
+
+ nil, /* enable */
+ nil, /* disable */
+ nil, /* load */
+ nil, /* move */
+};
M pc/vgas3.c => pc/vgas3.c +8 -3
@@ 567,15 567,20 @@ s3drawinit(VGAscr *scr)
* above.
*/
switch(id){
- case VIRGE: /* ViRGE */
- case VIRGEVX: /* ViRGE/VX */
- case VIRGEGX2: /* ViRGE/GX2 */
+ case VIRGE:
+ case VIRGEVX:
+ case VIRGEGX2:
scr->mmio = (ulong*)(scr->aperture+0x1000000);
scr->fill = hwfill;
scr->scroll = hwscroll;
/* scr->blank = hwblank; */
break;
+ case SAVAGEIXMV:
+ scr->mmio = (ulong*)(scr->aperture+0x1000000);
+ savageinit(scr);
+ break;
case SAVAGE4:
+ /* scr->mmio is set by s3linear */
savageinit(scr);
break;
}
M pc/vgasavage.c => pc/vgasavage.c +45 -7
@@ 69,7 69,7 @@ enum {
* 32-bit reads of the status registers seem just fine.
*/
-/* 2D graphics engine registers */
+/* 2D graphics engine registers for Savage4; others appear to be mostly the same */
enum {
SubsystemStatus = 0x8504, /* Subsystem Status: read only */
/* read only: whether we get interrupts on various events */
@@ 344,21 344,49 @@ enum {
};
+struct {
+ ulong idletimeout;
+} savagestats;
+
enum {
- Maxloop = 1<<23
+ Maxloop = 1<<25
};
static void
savagewaitidle(VGAscr *scr)
{
long x;
- ulong *statw;
-
- statw = (ulong*)((uchar*)scr->mmio+AltStatus0);
+ ulong *statw, mask, goal;
+
+ switch(scr->id){
+ case SAVAGE4:
+ statw = (ulong*)((uchar*)scr->mmio+AltStatus0);
+ mask = Ge2Idle;
+ goal = 0;
+ break;
+ /* case SAVAGEMXMV: ? */
+ /* case SAVAGEMX: ? */
+ /* case SAVAGEIXMV: ? */
+ /* case SAVAGEIX: ? */
+ case SAVAGEIXMV:
+ /* wait for engine idle and FIFO empty */
+ statw = (ulong*)((uchar*)scr->mmio+XStatus0);
+ mask = 0x0008FFFF;
+ goal = 0x00080000;
+ break;
+ default:
+ /*
+ * best we can do: can't print or we'll call ourselves.
+ * savageinit is supposed to not let this happen.
+ */
+ return;
+ }
for(x=0; x<Maxloop; x++)
- if(*statw & Ge2Idle)
+ if((*statw & mask) == goal)
return;
+
+ savagestats.idletimeout++;
}
static int
@@ 429,12 457,22 @@ savageinit(VGAscr *scr)
uchar *mmio;
ulong bd;
- mmio = (uchar*)scr->mmio;
+ /* if you add chip IDs here be sure to update savagewaitidle */
+ switch(scr->id){
+ case SAVAGE4:
+ case SAVAGEIXMV:
+ break;
+ default:
+ print("unknown savage %.4lux\n", scr->id);
+ return;
+ }
+ mmio = (uchar*)scr->mmio;
if(mmio == nil) {
print("savageinit: no mmio\n");
return;
}
+
/* 2D graphics engine software reset */
*(ushort*)(mmio+SubsystemCtl) = GeSoftReset;
delay(2);
M port/chan.c => port/chan.c +1 -1
@@ 641,7 641,7 @@ namec(char *name, int amode, int omode, ulong perm)
if(name[0] == 0)
error(Enonexist);
- if(!((ulong)name & KZERO)) {
+ if(((ulong)name & KZERO) != KZERO) {
p = name;
t = BY2PG-((ulong)p&(BY2PG-1));
while(vmemchr(p, 0, t) == 0) {
M port/fault.c => port/fault.c +1 -1
@@ 345,7 345,7 @@ vmemchr(void *s, int c, int n)
t = vmemchr(s, c, m);
if(t)
return t;
- if(!(a & KZERO))
+ if((a & KZERO) != KZERO)
validaddr(a+m, 1, 0);
return vmemchr((void*)(a+m), c, n-m);
}
M port/sysproc.c => port/sysproc.c +2 -2
@@ 242,7 242,7 @@ sysexec(ulong *arg)
text = l2be(exec.text);
entry = l2be(exec.entry);
if(n==sizeof(Exec) && (magic == AOUT_MAGIC)){
- if((text&KZERO)
+ if((text&KZERO) == KZERO
|| entry < UTZERO+sizeof(Exec)
|| entry >= UTZERO+sizeof(Exec)+text)
error(Ebadexec);
@@ 278,7 278,7 @@ sysexec(ulong *arg)
d = (t + data + (BY2PG-1)) & ~(BY2PG-1);
bssend = t + data + bss;
b = (bssend + (BY2PG-1)) & ~(BY2PG-1);
- if((t|d|b) & KZERO)
+ if(((t|d|b) & KZERO) == KZERO)
error(Ebadexec);
/*