M bitsy/devuda1341.c => bitsy/devuda1341.c +12 -7
@@ 517,7 517,8 @@ enable(void)
sspregs->control0 = 0x039f; /* enable */
/* Enable the audio power */
- egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 1);
+ audioicpower(1);
+ egpiobits(EGPIO_codec_reset, 1);
setspeed(0, 0, 0, 0, volumes[Vspeed].ilval);
@@ 672,7 673,7 @@ setreg(char *name, int val, int n)
static void
outenable(void) {
/* turn on DAC, set output gain switch */
- egpiobits(EGPIO_audio_power, 1);
+ audioamppower(1);
audiomute(0);
status1[0] |= 0x41;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
@@ 690,13 691,12 @@ outdisable(void) {
dmastop(audio.o.dma);
/* turn off DAC, clear output gain switch */
audiomute(1);
- egpiobits(EGPIO_audio_power, 0);
status1[0] &= ~0x41;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
if (debug) {
print("outdisable: status1 = 0x%2.2ux\n", status1[0]);
}
- egpiobits(EGPIO_audio_power, 0);
+ audioamppower(0);
}
static void
@@ 812,7 812,9 @@ audiopower(int flag) {
if (flag) {
/* power on only when necessary */
if (audio.amode) {
- egpiobits(EGPIO_audio_power | EGPIO_audio_ic_power | EGPIO_codec_reset, 1);
+ audioamppower(1);
+ audioicpower(1);
+ egpiobits(EGPIO_codec_reset, 1);
enable();
if (audio.amode & Aread) {
inenable();
@@ 834,7 836,9 @@ audiopower(int flag) {
indisable();
if (audio.amode & Awrite)
outdisable();
- egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset | EGPIO_audio_power, 0);
+ egpiobits(EGPIO_codec_reset, 0);
+ audioamppower(0);
+ audioicpower(0);
}
}
@@ 1020,7 1024,8 @@ audioclose(Chan *c)
}
if (audio.amode == 0) {
/* turn audio off */
- egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 0);
+ egpiobits(EGPIO_codec_reset, 0);
+ audioicpower(0);
}
qunlock(&audio);
}
M bitsy/fns.h => bitsy/fns.h +3 -0
@@ 1,6 1,8 @@
#include "../port/portfns.h"
void audiopower(int);
+void audioamppower(int);
+void audioicpower(int);
void cacheflush(void);
void cachewb(void);
void cachewbaddr(void*);
@@ 55,6 57,7 @@ void mmuenable(void);
void mmudisable(void);
void mmuinvalidate(void);
void mmuinvalidateaddr(ulong);
+void mmurestart(void);
ulong mmu_kaddr(ulong);
ulong mmu_paddr(ulong);
int µcputc(Queue*, int);
M bitsy/main.c => bitsy/main.c +17 -1
@@ 36,7 36,6 @@ main(void)
machinit();
trapinit();
sa1110_uartsetup(1);
- rs232power(1);
dmainit();
screeninit();
printinit(); /* from here on, print works, before this we need iprint */
@@ 423,18 422,35 @@ void
rs232power(int on)
{
egpiobits(EGPIO_rs232_power, on);
+ delay(50);
+}
+
+void
+audioamppower(int on)
+{
+ egpiobits(EGPIO_audio_power, on);
+ delay(50);
+}
+
+void
+audioicpower(int on)
+{
+ egpiobits(EGPIO_audio_ic_power, on);
+ delay(50);
}
void
irpower(int on)
{
egpiobits(EGPIO_ir_power, on);
+ delay(50);
}
void
lcdpower(int on)
{
egpiobits(EGPIO_lcd_3v|EGPIO_lcd_ic_power|EGPIO_lcd_5v|EGPIO_lcd_9v, on);
+ delay(50);
}
void
M bitsy/mmu.c => bitsy/mmu.c +7 -2
@@ 110,6 110,13 @@ mmuinit(void)
l1table[a>>20] = L1PageTable | L1Domain0 | (((ulong)t) & L1PTBaseMask);
t[(a&0xfffff)>>PGSHIFT] = L2SmallPage | L2KernelRW | (PHYSDRAM0 & L2PageBaseMask);
+ mmurestart();
+
+ mmuinited = 1;
+}
+
+void
+mmurestart(void) {
/* set up the domain register to cause all domains to obey pte access bits */
putdac(Dclient);
@@ 121,8 128,6 @@ mmuinit(void)
mmuinvalidate();
mmuenable();
cacheflush();
-
- mmuinited = 1;
}
/*
M bitsy/power.c => bitsy/power.c +44 -32
@@ 64,14 64,26 @@ intrcpy(Intrregs *to, Intrregs *from)
}
static void
-gpiocpy(GPIOregs *to, GPIOregs *from)
+gpiosave(GPIOregs *to, GPIOregs *from)
{
+ to->level = from->level;
to->rising = from->rising; // gpio intrs enabled
to->falling= from->falling; // gpio intrs enabled
to->altfunc = from->altfunc;
to->direction = from->direction;
}
+static void
+gpiorestore(GPIOregs *to, GPIOregs *from)
+{
+ to->rising = from->rising; // gpio intrs enabled
+ to->falling= from->falling; // gpio intrs enabled
+ to->altfunc = from->altfunc;
+ to->direction = from->direction;
+ to->set = from->level & 0x0fffffff;
+ to->clear = ~from->level & 0x0fffffff;
+}
+
void (*restart)(void) = nil;
static void
@@ 90,14 102,15 @@ sa1100_power_off(void)
powerregs->pcfr = PCFR_opde | PCFR_fp | PCFR_fs;
powerregs->pgsr = 0;
/* set resume address. The loader jumps to it */
-// powerregs->pspr = (ulong)sa1100_power_resume;
- powerregs->pspr = 0;
- /* set lowest clock; delay to avoid resume hangs on fast sa1110 */
+ powerregs->pspr = (ulong)sa1100_power_resume;
+// powerregs->pspr = 0;
-sa1100_power_resume();
- delay(90);
- powerregs->ppcr = 0;
- delay(90);
+//sa1100_power_resume();
+
+ /* set lowest clock; delay to avoid resume hangs on fast sa1110 */
+// delay(90);
+// powerregs->ppcr = 0;
+// delay(90);
/* set all GPIOs to input mode */
gpioregs->direction = 0;
@@ 131,12 144,30 @@ deepsleep(void) {
void *xsp, *xlink;
power_pl = splhi();
- cachewb();
- delay(500);
+ delay(50);
+ /* Power down */
+ iprint("entering suspend mode\n");
+ uartpower(0);
+ clockpower(0);
+ irpower(0);
+ audiopower(0);
+ screenpower(0);
+ µcpower(0);
+ rs232power(0);
+ gpiosave(&savedgpioregs, gpioregs);
+ intrcpy(&savedintrregs, intrregs);
+ cacheflush();
+ delay(50);
if (setpowerlabel()) {
- mmuinvalidate();
- mmuenable();
- cacheflush();
+ mmurestart();
+ gpiorestore(gpioregs, &savedgpioregs);
+ delay(50);
+ intrcpy(intrregs, &savedintrregs);
+ if (intrregs->icip & (1<<IRQgpio0)){
+ // don't want to sleep now. clear on/off irq.
+ gpioregs->edgestatus = (1<<IRQgpio0);
+ intrregs->icip = (1<<IRQgpio0);
+ }
trapresume();
rs232power(1);
uartpower(1);
@@ 144,13 175,6 @@ deepsleep(void) {
// audiopower(1);
clockpower(1);
gpclkregs->r0 = 1<<0;
- gpiocpy(gpioregs, &savedgpioregs);
- intrcpy(intrregs, &savedintrregs);
- if (intrregs->icip & (1<<IRQgpio0)){
- // don't want to sleep now. clear on/off irq.
- gpioregs->edgestatus = (1<<IRQgpio0);
- intrregs->icip = (1<<IRQgpio0);
- }
µcpower(1);
screenpower(1);
iprint("\nresuming execution\n");
@@ 159,18 183,6 @@ deepsleep(void) {
splx(power_pl);
return;
}
- /* Power down */
- iprint("entering suspend mode\n");
- gpiocpy(&savedgpioregs, gpioregs);
- intrcpy(&savedintrregs, intrregs);
- uartpower(0);
- delay(400);
- clockpower(0);
- irpower(0);
- audiopower(0);
- screenpower(0);
- µcpower(0);
- rs232power(0);
sa1100_power_off();
/* no return */
}
M bitsy/screen.c => bitsy/screen.c +18 -4
@@ 159,6 159,13 @@ static void
lcdinit(void)
{
/* the following line works because main memory is direct mapped */
+ gpioregs->direction |=
+ GPIO_LDD8_o|GPIO_LDD9_o|GPIO_LDD10_o|GPIO_LDD11_o
+ |GPIO_LDD12_o|GPIO_LDD13_o|GPIO_LDD14_o|GPIO_LDD15_o;
+ gpioregs->altfunc |=
+ GPIO_LDD8_o|GPIO_LDD9_o|GPIO_LDD10_o|GPIO_LDD11_o
+ |GPIO_LDD12_o|GPIO_LDD13_o|GPIO_LDD14_o|GPIO_LDD15_o;
+ framebuf->palette[0] = Pal0;
lcd->dbar1 = framebuf->palette;
lcd->lccr3 = pcd<<PCD | 0<<ACB | 0<<API | 1<<VSP | 1<<HSP | 0<<PCP | 0<<OEP;
lcd->lccr2 = (Wid-1)<<LPP | vsw<<VSW | efw<<EFW | bfw<<BFW;
@@ 217,8 224,6 @@ screeninit(void)
vscreen = xalloc(sizeof(ushort)*Wid*Ht);
- framebuf->palette[0] = Pal0;
-
lcdpower(1);
lcdinit();
@@ 304,9 309,18 @@ setcolor(ulong p, ulong r, ulong g, ulong b)
void
blankscreen(int blank)
{
+ int cnt;
+
if (blank) {
- lcd->lccr0 &= ~(0<<LEN); /* disable the LCD */
- delay(100);
+ lcd->lccr0 &= ~(1<<LEN); /* disable the LCD */
+ cnt = 0;
+ while((lcd->lcsr & (1<<LDD)) == 0) {
+ delay(10);
+ if (++cnt == 100) {
+ iprint("LCD doesn't stop\n");
+ break;
+ }
+ }
lcdpower(0);
} else {
lcdpower(1);
A mtx/dat.h => mtx/dat.h +226 -0
@@ 0,0 1,226 @@
+typedef struct Conf Conf;
+typedef struct FPsave FPsave;
+typedef struct ISAConf ISAConf;
+typedef struct Label Label;
+typedef struct Lock Lock;
+typedef struct Mach Mach;
+typedef struct Notsave Notsave;
+typedef struct Page Page;
+typedef struct PCArch PCArch;
+typedef struct PCB PCB;
+typedef struct Pcidev Pcidev;
+typedef struct PMMU PMMU;
+typedef struct Proc Proc;
+typedef struct Sys Sys;
+typedef struct Ureg Ureg;
+typedef struct Vctl Vctl;
+
+#define MAXSYSARG 5 /* for mount(fd, mpt, flag, arg, srv) */
+
+/*
+ * parameters for sysproc.c
+ */
+#define AOUT_MAGIC Q_MAGIC
+
+/*
+ * machine dependent definitions used by ../port/dat.h
+ */
+
+struct Lock
+{
+ ulong key; /* semaphore (non-zero = locked) */
+ ulong sr;
+ ulong pc;
+ Proc *p;
+ ulong pid;
+ ushort isilock;
+};
+
+struct Label
+{
+ ulong sp;
+ ulong pc;
+};
+
+/*
+ * FPsave.fpstatus
+ */
+enum
+{
+ FPinit,
+ FPactive,
+ FPinactive,
+};
+
+struct FPsave
+{
+int dummy;
+};
+
+struct Conf
+{
+ ulong nmach; /* processors */
+ ulong nproc; /* processes */
+ ulong npage0; /* total physical pages of memory */
+ ulong npage1; /* total physical pages of memory */
+ ulong npage; /* total physical pages of memory */
+ ulong base0; /* base of bank 0 */
+ ulong base1; /* base of bank 1 */
+ ulong upages; /* user page pool */
+ ulong nimage; /* number of page cache image headers */
+ ulong nswap; /* number of swap pages */
+ int nswppo; /* max # of pageouts per segment pass */
+ ulong copymode; /* 0 is copy on write, 1 is copy on reference */
+ int monitor; /* has display? */
+ ulong ialloc; /* bytes available for interrupt time allocation */
+ ulong pipeqsize; /* size in bytes of pipe queues */
+};
+
+/*
+ * mmu goo in the Proc structure
+ */
+struct PMMU
+{
+int dummy;
+};
+
+/*
+ * things saved in the Proc structure during a notify
+ */
+struct Notsave
+{
+ ulong UNUSED;
+};
+
+#include "../port/portdat.h"
+
+/*
+ * machine dependent definitions not used by ../port/dat.h
+ */
+/*
+ * Fake kmap
+ */
+typedef void KMap;
+#define VA(k) ((ulong)(k))
+#define kmap(p) (KMap*)((p)->pa|KZERO)
+#define kunmap(k)
+
+/*
+ * Process Control Block, used by PALcode
+ */
+struct PCB {
+ uvlong ksp;
+ uvlong usp;
+ uvlong ptbr;
+ ulong asn;
+ ulong pcc;
+ uvlong unique;
+ ulong fen;
+ ulong dummy;
+ uvlong rsrv1;
+ uvlong rsrv2;
+};
+
+struct Mach
+{
+ /* OFFSETS OF THE FOLLOWING KNOWN BY l.s */
+ int machno; /* physical id of processor */
+ ulong splpc; /* pc that called splhi() */
+ Proc *proc; /* current process on this processor */
+
+ /* ordering from here on irrelevant */
+
+ ulong ticks; /* of the clock since boot time */
+ Label sched; /* scheduler wakeup */
+ Lock alarmlock; /* access to alarm list */
+ void *alarm; /* alarms bound to this clock */
+ int inclockintr;
+
+ ulong fairness; /* for runproc */
+
+ ulong cpuhz; /* hwrpb->cfreq */
+ ulong pcclast;
+ uvlong fastclock;
+ vlong intrts; /* time stamp of last interrupt */
+
+ int tlbfault; /* only used by devproc; no access to tlb */
+ int tlbpurge; /* ... */
+ int pfault;
+ int cs;
+ int syscall;
+ int load;
+ int intr;
+ int flushmmu; /* make current proc flush it's mmu state */
+
+ ulong spuriousintr;
+ int lastintr;
+
+ PCB;
+
+ /* MUST BE LAST */
+ int stack[1];
+};
+
+struct
+{
+ Lock;
+ short machs;
+ short exiting;
+ short ispanic;
+}active;
+
+/*
+ * Implementation-dependant functions (outside of Alpha architecture proper).
+ * Called PCArch because that's what mkdevc calls it (for the PC).
+ */
+struct PCArch
+{
+ char* id;
+ int (*ident)(void);
+
+ void (*coreinit)(void); /* set up core logic, PCI mappings etc */
+ void (*corehello)(void); /* identify core logic to user */
+ void (*coredetach)(void); /* restore core logic before return to console */
+ void *(*pcicfg)(int, int); /* map and point to PCI cfg space */
+ void *(*pcimem)(int, int); /* map and point to PCI memory space */
+ int (*intrenable)(Vctl*);
+
+ int (*_inb)(int);
+ ushort (*_ins)(int);
+ ulong (*_inl)(int);
+ void (*_outb)(int, int);
+ void (*_outs)(int, ushort);
+ void (*_outl)(int, ulong);
+ void (*_insb)(int, void*, int);
+ void (*_inss)(int, void*, int);
+ void (*_insl)(int, void*, int);
+ void (*_outsb)(int, void*, int);
+ void (*_outss)(int, void*, int);
+ void (*_outsl)(int, void*, int);
+};
+
+/*
+ * a parsed plan9.ini line
+ */
+#define NISAOPT 8
+
+struct ISAConf {
+ char *type;
+ ulong port;
+ ulong irq;
+ ulong dma;
+ ulong mem;
+ ulong size;
+ ulong freq;
+
+ int nopt;
+ char *opt[NISAOPT];
+};
+
+extern PCArch *arch;
+
+#define MACHP(n) ((Mach *)((int)&mach0+n*BY2PG))
+extern Mach mach0;
+
+extern register Mach *m;
+extern register Proc *up;
A mtx/fns.h => mtx/fns.h +106 -0
@@ 0,0 1,106 @@
+#include "../port/portfns.h"
+
+void archinit(void);
+int brgalloc(void);
+void brgfree(int);
+ulong baudgen(int, int);
+int cistrcmp(char*, char*);
+int cistrncmp(char*, char*, int);
+void clockcheck(void);
+void clockinit(void);
+void clockintr(Ureg*);
+void clrfptrap(void);
+#define coherence()
+void cpminit(void);
+int cpuidentify(void);
+void cpuidprint(void);
+void dcflush(void*, ulong);
+void delay(int);
+ulong draminit(ulong*);
+void dtlbmiss(void);
+void dtlberror(void);
+void dumpregs(Ureg*);
+void delayloopinit(void);
+void eieio(void);
+//#define eieio()
+void evenaddr(ulong);
+void faultpower(Ureg*, ulong addr, int read);
+void firmware(int);
+void fpinit(void);
+int fpipower(Ureg*);
+void fpoff(void);
+ulong fpstatus(void);
+char* getconf(char*);
+ulong getdar(void);
+ulong getdec(void);
+ulong getdepn(void);
+ulong getdsisr(void);
+ulong getimmr(void);
+ulong getmsr(void);
+ulong getpvr(void);
+ulong gettbl(void);
+ulong gettbu(void);
+void gotopc(ulong);
+void i8250console(void);
+void icflush(void*, ulong);
+void idle(void);
+#define idlehands() /* nothing to do in the runproc */
+int inb(int);
+void insb(int, void*, int);
+ushort ins(int);
+void inss(int, void*, int);
+ulong inl(int);
+void insl(int, void*, int);
+void intr(Ureg*);
+void intrenable(int, void (*)(Ureg*, void*), void*, int, char*);
+int intrstats(char*, int);
+void intrvec(void);
+int iprint(char*, ...);
+void itlbmiss(void);
+int isaconfig(char*, int, ISAConf*);
+void kbdinit(void);
+void kbdreset(void);
+void kernelmmu(void);
+void links(void);
+void mathinit(void);
+void mmuinit(void);
+ulong* mmuwalk(ulong*, ulong, int);
+void outb(int, int);
+void outsb(int, void*, int);
+void outs(int, ushort);
+void outss(int, void*, int);
+void outl(int, ulong);
+void outsl(int, void*, int);
+int pcmspecial(char*, ISAConf*);
+void pcmspecialclose(int);
+#define procrestore(p)
+void powerdownled(void);
+void powerupled(void);
+void procsave(Proc*);
+void procsetup(Proc*);
+void putdec(ulong);
+void putmsr(ulong);
+void putcasid(ulong);
+void screeninit(void);
+void setpanic(void);
+int screenprint(char*, ...); /* debugging */
+ulong sdraminit(ulong*);
+int segflush(void*, ulong);
+void spireset(void);
+long spioutin(void*, long, void*);
+int tas(void*);
+uchar* tarlookup(uchar *addr, char *file, int *dlen);
+void touser(void*);
+void trapinit(void);
+void trapvec(void);
+void tlbflush(ulong);
+void tlbflushall(void);
+void uartinstall(void);
+void uartwait(void); /* debugging */
+int unsac(uchar *dst, uchar *src, int n, int nsrc);
+#define userureg(ur) ((ur)->status & KUSER)
+void wbflush(void);
+
+#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
+#define KADDR(a) ((void*)((ulong)(a)|KZERO))
+#define PADDR(a) ((ulong)(a)&~KZERO)
A mtx/inb.s => mtx/inb.s +119 -0
@@ 0,0 1,119 @@
+#include "mem.h"
+
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+
+TEXT inb(SB), $0
+ OR $IOMEM, R3
+ MOVBZ (R3), R3
+ RETURN
+
+TEXT insb(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $IOMEM, R3
+ SUB $1, R4
+insb1:
+ MOVBZ (R3), R7
+ MOVBU R7, 1(R4)
+ BDNZ insb1
+ RETURN
+
+TEXT outb(SB), $0
+ MOVW v+4(FP), R4
+ OR $IOMEM, R3
+ EIEIO
+ MOVB R4, (R3)
+ RETURN
+
+TEXT outsb(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $IOMEM, R3
+ SUB $1, R4
+outsb1:
+ EIEIO
+ MOVBZU 1(R4), R7
+ MOVB R7, (R3)
+ BDNZ outsb1
+ RETURN
+
+TEXT ins(SB), $0
+ OR $IOMEM, R3
+ EIEIO
+ MOVHBR (R3), R3
+ RETURN
+
+TEXT inss(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $IOMEM, R3
+ SUB $2, R4
+inss1:
+ EIEIO
+ MOVHZ (R3), R7
+ MOVHU R7, 2(R4)
+ BDNZ inss1
+ RETURN
+
+TEXT outs(SB), $0
+ MOVW v+4(FP), R4
+ OR $IOMEM, R3
+ EIEIO
+ MOVHBR R4, (R3)
+ RETURN
+
+TEXT outss(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $IOMEM, R3
+ SUB $2, R4
+outss1:
+ EIEIO
+ MOVHZU 2(R4), R7
+ MOVH R7, (R3)
+ BDNZ outss1
+ RETURN
+
+TEXT inl(SB), $0
+ OR $IOMEM, R3
+ EIEIO
+ MOVWBR (R3), R3
+ RETURN
+
+TEXT insl(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $IOMEM, R3
+ SUB $4, R4
+insl1:
+ EIEIO
+ MOVW (R3), R7
+ MOVWU R7, 4(R4)
+ BDNZ insl1
+ RETURN
+
+TEXT outl(SB), $0
+ MOVW v+4(FP), R4
+ OR $IOMEM, R3
+ EIEIO
+ MOVWBR R4, (R3)
+ RETURN
+
+TEXT outsl(SB), $0
+ MOVW v+4(FP), R4
+ MOVW n+8(FP), R5
+ MOVW R5, CTR
+ OR $IOMEM, R3
+ SUB $4, R4
+outsl1:
+ EIEIO
+ MOVWU 4(R4), R7
+ MOVW R7, (R3)
+ BDNZ outsl1
+ RETURN
A mtx/io.h => mtx/io.h +159 -0
@@ 0,0 1,159 @@
+enum {
+ IrqCLOCK = 0,
+ IrqKBD = 1,
+ IrqUART1 = 3,
+ IrqUART0 = 4,
+ IrqPCMCIA = 5,
+ IrqFLOPPY = 6,
+ IrqLPT = 7,
+ IrqIRQ7 = 7,
+ IrqAUX = 12, /* PS/2 port */
+ IrqIRQ13 = 13, /* coprocessor on 386 */
+ IrqATA0 = 14,
+ IrqATA1 = 15,
+ MaxIrqPIC = 15,
+
+ VectorPIC = 64,
+ MaxVectorPIC = VectorPIC+MaxIrqPIC,
+};
+
+typedef struct Vctl {
+ Vctl* next; /* handlers on this vector */
+
+ char name[KNAMELEN]; /* of driver */
+ int isintr; /* interrupt or fault/trap */
+ int irq;
+ int tbdf;
+ int (*isr)(int); /* get isr bit for this irq */
+ int (*eoi)(int); /* eoi */
+
+ void (*f)(Ureg*, void*); /* handler to call */
+ void* a; /* argument to call it with */
+} Vctl;
+
+enum {
+ BusCBUS = 0, /* Corollary CBUS */
+ BusCBUSII, /* Corollary CBUS II */
+ BusEISA, /* Extended ISA */
+ BusFUTURE, /* IEEE Futurebus */
+ BusINTERN, /* Internal bus */
+ BusISA, /* Industry Standard Architecture */
+ BusMBI, /* Multibus I */
+ BusMBII, /* Multibus II */
+ BusMCA, /* Micro Channel Architecture */
+ BusMPI, /* MPI */
+ BusMPSA, /* MPSA */
+ BusNUBUS, /* Apple Macintosh NuBus */
+ BusPCI, /* Peripheral Component Interconnect */
+ BusPCMCIA, /* PC Memory Card International Association */
+ BusTC, /* DEC TurboChannel */
+ BusVL, /* VESA Local bus */
+ BusVME, /* VMEbus */
+ BusXPRESS, /* Express System Bus */
+};
+
+#define MKBUS(t,b,d,f) (((t)<<24)|(((b)&0xFF)<<16)|(((d)&0x1F)<<11)|(((f)&0x07)<<8))
+#define BUSFNO(tbdf) (((tbdf)>>8)&0x07)
+#define BUSDNO(tbdf) (((tbdf)>>11)&0x1F)
+#define BUSBNO(tbdf) (((tbdf)>>16)&0xFF)
+#define BUSTYPE(tbdf) ((tbdf)>>24)
+#define BUSDF(tbdf) ((tbdf)&0x000FF00)
+#define BUSBDF(tbdf) ((tbdf)&0x0FFFF00)
+#define BUSUNKNOWN (-1)
+
+enum {
+ MaxEISA = 16,
+ EISAconfig = 0xC80,
+};
+
+/*
+ * PCI support code.
+ */
+enum { /* type 0 and type 1 pre-defined header */
+ PciVID = 0x00, /* vendor ID */
+ PciDID = 0x02, /* device ID */
+ PciPCR = 0x04, /* command */
+ PciPSR = 0x06, /* status */
+ PciRID = 0x08, /* revision ID */
+ PciCCRp = 0x09, /* programming interface class code */
+ PciCCRu = 0x0A, /* sub-class code */
+ PciCCRb = 0x0B, /* base class code */
+ PciCLS = 0x0C, /* cache line size */
+ PciLTR = 0x0D, /* latency timer */
+ PciHDT = 0x0E, /* header type */
+ PciBST = 0x0F, /* BIST */
+
+ PciBAR0 = 0x10, /* base address */
+ PciBAR1 = 0x14,
+ PciROM = 0x30,
+
+ PciINTL = 0x3C, /* interrupt line */
+ PciINTP = 0x3D, /* interrupt pin */
+};
+
+enum { /* type 0 pre-defined header */
+ PciBAR2 = 0x18,
+ PciBAR3 = 0x1C,
+ PciBAR4 = 0x20,
+ PciBAR5 = 0x24,
+ PciCIS = 0x28, /* cardbus CIS pointer */
+ PciSVID = 0x2C, /* subsystem vendor ID */
+ PciSID = 0x2E, /* cardbus CIS pointer */
+ PciEBAR0 = 0x30, /* xpansion ROM base address */
+ PciMGNT = 0x3E, /* burst period length */
+ PciMLT = 0x3F, /* maximum latency between bursts */
+};
+
+enum { /* type 1 pre-defined header */
+ PciPBN = 0x18, /* primary bus number */
+ PciSBN = 0x19, /* secondary bus number */
+ PciUBN = 0x1A, /* subordinate bus number */
+ PciSLTR = 0x1B, /* secondary latency timer */
+ PciIBR = 0x1C, /* I/O base */
+ PciILR = 0x1D, /* I/O limit */
+ PciSPSR = 0x1E, /* secondary status */
+ PciMBR = 0x20, /* memory base */
+ PciMLR = 0x22, /* memory limit */
+ PciPMBR = 0x24, /* prefetchable memory base */
+ PciPMLR = 0x26, /* prefetchable memory limit */
+ PciPUBR = 0x28, /* prefetchable base upper 32 bits */
+ PciPULR = 0x2C, /* prefetchable limit upper 32 bits */
+ PciIUBR = 0x30, /* I/O base upper 16 bits */
+ PciIULR = 0x32, /* I/O limit upper 16 bits */
+ PciEBAR1 = 0x28, /* expansion ROM base address */
+ PciBCR = 0x3E, /* bridge control register */
+};
+
+typedef struct Pcidev Pcidev;
+typedef struct Pcidev {
+ int tbdf; /* type+bus+device+function */
+ ushort vid; /* vendor ID */
+ ushort did; /* device ID */
+
+ uchar rid;
+ uchar ccrp;
+ uchar ccru;
+ uchar ccrb;
+
+ struct {
+ ulong bar; /* base address */
+ int size;
+ } mem[6];
+
+ uchar intl; /* interrupt line */
+
+ Pcidev* list;
+ Pcidev* link; /* next device on this bno */
+
+ Pcidev* bridge; /* down a bus */
+ struct {
+ ulong bar;
+ int size;
+ } ioa, mema;
+ ulong pcr;
+};
+
+//#define PCIWINDOW 0x40000000
+//#define PCIWADDR(va) (PADDR(va)+PCIWINDOW)
+//#define ISAWINDOW 0x00800000
+//#define ISAWADDR(va) (PADDR(va)+ISAWINDOW)
A mtx/l.s => mtx/l.s +71 -0
@@ 0,0 1,71 @@
+#include "mem.h"
+#include "mpc60x.h"
+
+#define BDNZ BC 16,0,
+#define BDNE BC 0,2,
+#define NOOP OR R0,R0,R0
+#define TLBIA WORD $(31<<26)
+
+/* Be-ware 603e chip bugs (mtmsr instruction) */
+#define FIX603e CROR 0,0,0
+#undef FIX603e
+#define FIX603e ISYNC; SYNC
+
+ TEXT start(SB), $-4
+ MOVW $setSB(SB), R2
+
+ BL main(SB)
+ RETURN /* not reached */
+
+TEXT splhi(SB), $0
+ MOVW LR, R31
+ MOVW R31, 4(R(MACH)) /* save PC in m->splpc */
+ MOVW MSR, R3
+ RLWNM $0, R3, $~MSR_EE, R4
+ SYNC
+ MOVW R4, MSR
+ FIX603e
+ RETURN
+
+TEXT splx(SB), $0
+ /* fall though */
+
+TEXT splxpc(SB), $0
+ MOVW LR, R31
+ MOVW R31, 4(R(MACH)) /* save PC in m->splpc */
+ MOVW MSR, R4
+ RLWMI $0, R3, $MSR_EE, R4
+ SYNC
+ MOVW R4, MSR
+ FIX603e
+ RETURN
+
+TEXT spllo(SB), $0
+ MOVW MSR, R3
+ OR $MSR_EE, R3, R4
+ SYNC
+ MOVW R4, MSR
+ FIX603e
+ RETURN
+
+TEXT spldone(SB), $0
+ RETURN
+
+TEXT islo(SB), $0
+ MOVW MSR, R3
+ RLWNM $0, R3, $MSR_EE, R3
+ RETURN
+
+TEXT setlabel(SB), $-4
+ MOVW LR, R31
+ MOVW R1, 0(R3)
+ MOVW R31, 4(R3)
+ MOVW $0, R3
+ RETURN
+
+TEXT gotolabel(SB), $-4
+ MOVW 4(R3), R31
+ MOVW R31, LR
+ MOVW 0(R3), R1
+ MOVW $1, R3
+ RETURN
A mtx/main.c => mtx/main.c +22 -0
@@ 0,0 1,22 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "init.h"
+#include "pool.h"
+
+Conf conf;
+FPsave initfp;
+
+void
+main(void)
+{
+// xinit();
+ printinit();
+ i8250console();
+ print("\nPlan 9\n");
+
+ for(;;);
+}
A mtx/mem.h => mtx/mem.h +101 -0
@@ 0,0 1,101 @@
+/* none of this is meant to be correct yet */
+
+/*
+ * 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 vlong */
+#define BY2PG 8192 /* bytes per page */
+#define WD2PG (BY2PG/BY2WD) /* words per page */
+#define PGSHIFT 13 /* log(BY2PG) */
+#define ROUND(s, sz) (((s)+(sz-1))&~(sz-1))
+#define PGROUND(s) ROUND(s, BY2PG)
+#define BLOCKALIGN 8
+
+#define BY2PTE 8 /* bytes per pte entry */
+#define PTE2PG (BY2PG/BY2PTE) /* pte entries per page */
+
+#define MAXMACH 1 /* max # cpus system can run */
+#define KSTACK 4096 /* Size of kernel stack */
+
+/*
+ * Time
+ */
+#define HZ 100 /* clock frequency */
+#define MS2HZ (1000/HZ)
+#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
+#define MS2TK(t) (((t)*HZ+500)/1000) /* milliseconds to closest tick */
+
+/*
+ * Magic registers
+ */
+
+#define MACH 30 /* R30 is m-> */
+#define USER 29 /* R29 is up-> */
+
+
+/*
+ * Fundamental addresses
+ */
+
+#define UREGSIZE ((8+32)*4)
+
+/*
+ * MMU
+ *
+ */
+
+/* L1 table entry and Mx_TWC flags */
+#define PTEVALID (1<<0)
+#define PTEWT (1<<1) /* write through */
+#define PTE4K (0<<2)
+#define PTE512K (1<<2)
+#define PTE8MB (3<<2)
+#define PTEG (1<<4) /* guarded */
+
+/* L2 table entry and Mx_RPN flags (also PTEVALID) */
+#define PTECI (1<<1) /* cache inhibit */
+#define PTESH (1<<2) /* page is shared; ASID ignored */
+#define PTELPS (1<<3) /* large page size */
+#define PTEWRITE 0x9F0
+
+/* TLB and MxEPN flag */
+#define TLBVALID (1<<9)
+
+#define TLBSETS 32 /* number of tlb sets (603/603e) */
+
+#define PTEMAPMEM (1024*1024)
+#define PTEPERTAB (PTEMAPMEM/BY2PG)
+#define SEGMAPSIZE 512
+#define SSEGMAPSIZE 16
+
+/*
+ * Address spaces
+ */
+
+#define UZERO 0 /* base of user address space */
+#define UTZERO (UZERO+BY2PG) /* first address in user text */
+#define USTKTOP (TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */
+#define TSTKTOP KZERO /* top of temporary stack */
+#define TSTKSIZ 100
+#define KZERO 0x80000000 /* base of kernel address space */
+#define KTZERO (KZERO+0x400000) /* first address in kernel text */
+#define USTKSIZE (4*1024*1024) /* size of user stack */
+
+#define PCI1 0x40000000
+#define PCI0 0xfd000000
+#define IOMEM 0xfe000000
+#define FALCON 0xfef80000
+#define RAVEN 0xfeff0000
+#define FLASHA 0xff000000
+#define FLASHB 0xff800000
+#define FLASHAorB 0xfff00000
+
+#define isphys(x) (((ulong)x&KZERO)!=0)
A mtx/trap.c => mtx/trap.c +828 -0
@@ 0,0 1,828 @@
+#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"
+
+enum
+{
+ Maxhandler= 32+16, /* max number of interrupt handlers */
+};
+
+typedef struct Handler Handler;
+struct Handler
+{
+ void (*r)(Ureg*, void*);
+ void *arg;
+ Handler *next;
+ int edge;
+ int nintr;
+ ulong ticks;
+ int maxtick;
+};
+
+struct
+{
+ Handler *ivec[128];
+ Handler h[Maxhandler];
+ int free;
+} halloc;
+
+void faultpower(Ureg *ur, ulong addr, int read);
+void kernfault(Ureg*, int);
+void syscall(Ureg* ureg);
+void noted(Ureg*, ulong);
+void reset(void);
+
+char *excname[] =
+{
+ "reserved 0",
+ "system reset",
+ "machine check",
+ "data access",
+ "instruction access",
+ "external interrupt",
+ "alignment",
+ "program exception",
+ "floating-point unavailable",
+ "decrementer",
+ "i/o controller interface error",
+ "reserved B",
+ "system call",
+ "trace trap",
+ "floating point assist",
+ "reserved F",
+ "software emulation",
+ "ITLB miss",
+ "DTLB miss",
+ "ITLB error",
+ "DTLB error",
+ "reserved 15",
+ "reserved 16",
+ "reserved 17",
+ "reserved 18",
+ "reserved 19",
+ "reserved 1A",
+ "reserved 1B",
+ "data breakpoint",
+ "instruction breakpoint",
+ "peripheral breakpoint",
+ "development port",
+ /* the following are made up on a program exception */
+ "floating point exception", /* 20: FPEXC */
+ "illegal instruction", /* 21 */
+ "privileged instruction", /* 22 */
+ "trap", /* 23 */
+ "illegal operation", /* 24 */
+ "breakpoint", /* 25 */
+};
+
+char *fpcause[] =
+{
+ "inexact operation",
+ "division by zero",
+ "underflow",
+ "overflow",
+ "invalid operation",
+};
+char *fpexcname(Ureg*, ulong, char*);
+#define FPEXPMASK 0xfff80300 /* Floating exception bits in fpscr */
+
+
+char *regname[]={
+ "CAUSE", "SRR1",
+ "PC", "GOK",
+ "LR", "CR",
+ "XER", "CTR",
+ "R0", "R1",
+ "R2", "R3",
+ "R4", "R5",
+ "R6", "R7",
+ "R8", "R9",
+ "R10", "R11",
+ "R12", "R13",
+ "R14", "R15",
+ "R16", "R17",
+ "R18", "R19",
+ "R20", "R21",
+ "R22", "R23",
+ "R24", "R25",
+ "R26", "R27",
+ "R28", "R29",
+ "R30", "R31",
+};
+
+void
+sethvec(int v, void (*r)(void))
+{
+ ulong *vp, pa, o;
+
+ vp = KADDR(v);
+ vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */
+ vp[1] = 0x7c0802a6; /* MOVW LR, R0 */
+ vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */
+ pa = PADDR(r);
+ o = pa >> 25;
+ if(o != 0 && o != 0x7F){
+ /* a branch too far */
+ vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */
+ vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */
+ vp[5] = 0x7c0803a6; /* MOVW R0, LR */
+ vp[6] = 0x4e800021; /* BL (LR) */
+ }else
+ vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */
+ dcflush(vp, 8*sizeof(ulong));
+}
+
+void
+sethvec2(int v, void (*r)(void))
+{
+ ulong *vp;
+
+ vp = (ulong*)KADDR(v);
+ vp[0] = (18<<26)|(PADDR(r))|2; /* ba */
+ dcflush(vp, sizeof(*vp));
+}
+
+void
+trap(Ureg *ur)
+{
+ int ecode;
+ static struct {int callsched;} c = {1};
+ int user = (ur->srr1 & MSR_PR) != 0;
+ char buf[ERRLEN];
+
+ m->intrts = fastticks(nil);
+ ecode = (ur->cause >> 8) & 0xff;
+
+if(ur->status & MSR_RI == 0)
+print("double fault?: ecode = %d\n", ecode);
+ switch(ecode){
+ case CEI:
+ intr(ur);
+ break;
+
+ case CDEC:
+ clockintr(ur);
+ break;
+ case CIMISS:
+ faultpower(ur, ur->pc, 1);
+ break;
+ case CITLBE:
+ faultpower(ur, ur->pc, 1);
+ break;
+ case CDMISS:
+if(0) print("CDMISS: %lux %lux\n", m->epn, m->cmp1);
+ faultpower(ur, m->dar, 1);
+ break;
+ case CDTLBE:
+ faultpower(ur, m->dar, !(m->dsisr & (1<<25)));
+ break;
+
+ case CEMU:
+ print("CEMU: pc=#%lux op=#%8.8lux\n", ur->pc, *(ulong*)ur->pc);
+ sprint(buf, "sys: trap: illegal op addr=0x%lux", ur->pc);
+ postnote(up, 1, buf, NDebug);
+ break;
+
+ case CSYSCALL:
+ syscall(ur);
+ break;
+
+ case CPROG:
+ if(ur->status & (1<<19))
+ ecode = 0x20;
+ if(ur->status & (1<<18))
+ ecode = 0x21;
+ if(ur->status & (1<<17))
+ ecode = 0x22;
+ goto Default;
+
+ Default:
+ default:
+ spllo();
+ print("ecode = %d\n", ecode);
+ if(ecode < 0 || ecode >= 0x1F)
+ ecode = 0x1F;
+ print("kernel %s pc=0x%lux\n", excname[ecode], ur->pc);
+ dumpregs(ur);
+ dumpstack();
+ delay(100);
+ reset();
+ }
+
+ splhi();
+ if(user)
+ notify(ur);
+}
+
+void
+faultpower(Ureg *ureg, ulong addr, int read)
+{
+ int user, insyscall, n;
+ char buf[ERRLEN];
+ user = (ureg->srr1 & MSR_PR) != 0;
+if(0)print("fault: pid=%ld pc = %lux, addr = %lux read = %d user = %d stack=%ulx\n", up->pid, ureg->pc, addr, read, user, &ureg);
+ insyscall = up->insyscall;
+ up->insyscall = 1;
+ spllo();
+ n = fault(addr, read);
+ if(n < 0){
+ if(!user){
+ dumpregs(ureg);
+ panic("fault: 0x%lux\n", addr);
+ }
+print("fault: pid=%ld pc = %lux, addr = %lux read = %d user = %d stack=%ulx\n", up->pid, ureg->pc, addr, read, user, &ureg);
+dumpregs(ureg);
+ sprint(buf, "sys: trap: fault %s addr=0x%lux",
+ read? "read" : "write", addr);
+ postnote(up, 1, buf, NDebug);
+ }
+ up->insyscall = insyscall;
+}
+
+void
+spurious(Ureg *ur, void *a)
+{
+ USED(a);
+ print("SPURIOUS interrupt pc=0x%lux cause=0x%lux\n",
+ ur->pc, ur->cause);
+ panic("bad interrupt");
+}
+
+#define LEV(n) (((n)<<1)|1)
+#define IRQ(n) (((n)<<1)|0)
+
+Lock veclock;
+
+void
+trapinit(void)
+{
+ int i;
+ IMM *io;
+
+
+ io = m->iomem;
+ io->sypcr &= ~(1<<3); /* disable watchdog (821/823) */
+ io->simask = 0; /* mask all */
+ io->siel = ~0; /* edge sensitive, wake on all */
+ io->cicr = 0; /* disable CPM interrupts */
+ io->cipr = ~0; /* clear all interrupts */
+ io->cimr = 0; /* mask all events */
+ io->cicr = (0xE1<<16)|(CPIClevel<<13)|(0x1F<<8);
+ io->cicr |= 1 << 7; /* enable */
+ io->tbscr = 1; /* TBE */
+ io->simask |= 1<<(31-LEV(CPIClevel)); /* CPM's level */
+ eieio();
+ putdec(~0);
+
+ /*
+ * set all exceptions to trap
+ */
+ for(i = 0x0; i < 0x2000; i += 0x100)
+ sethvec(i, trapvec);
+
+ //sethvec(CEI<<8, intrvec);
+ sethvec2(CIMISS<<8, itlbmiss);
+ sethvec2(CDMISS<<8, dtlbmiss);
+ sethvec2(CDTLBE<<8, dtlberror);
+}
+
+void
+intrenable(int v, void (*r)(Ureg*, void*), void *arg, int, char *name)
+{
+ Handler *h;
+ IMM *io;
+
+ if(halloc.free >= Maxhandler)
+ panic("out of interrupt handlers");
+ v -= VectorPIC;
+ if(v < 0 || v >= nelem(halloc.ivec))
+ panic("intrenable(%d)", v+VectorPIC);
+ ilock(&veclock);
+ if(v < VectorCPIC || (h = halloc.ivec[v]) == nil){
+ h = &halloc.h[halloc.free++];
+ h->next = halloc.ivec[v];
+ halloc.ivec[v] = h;
+ }
+ h->r = r;
+ h->arg = arg;
+
+ /*
+ * enable corresponding interrupt in SIU/CPM
+ */
+
+ eieio();
+ io = m->iomem;
+ if(v >= VectorCPIC){
+ v -= VectorCPIC;
+ io->cimr |= 1<<(v&0x1F);
+ }
+ else if(v >= VectorIRQ)
+ io->simask |= 1<<(31-IRQ(v&7));
+ else
+ io->simask |= 1<<(31-LEV(v));
+ eieio();
+ iunlock(&veclock);
+}
+
+void
+intr(Ureg *ur)
+{
+ int b, v;
+ IMM *io;
+ Handler *h;
+ long t0;
+
+ ur->cause &= ~0xff;
+ io = m->iomem;
+ b = io->sivec>>2;
+ v = b>>1;
+ if(b & 1) {
+ if(v == CPIClevel){
+ io->civr = 1;
+ eieio();
+ v = VectorCPIC+(io->civr>>11);
+ }
+ }else
+ v += VectorIRQ;
+ ur->cause |= v;
+ h = halloc.ivec[v];
+ if(h == nil){
+ print("unknown interrupt %d pc=0x%lux\n", v, ur->pc);
+ uartwait();
+ return;
+ }
+ if(h->edge){
+ io->sipend |= 1<<(31-b);
+ eieio();
+ }
+ /*
+ * call the interrupt handlers
+ */
+ do {
+ h->nintr++;
+ t0 = getdec();
+ (*h->r)(ur, h->arg);
+ t0 -= getdec();
+ h->ticks += t0;
+ if(h->maxtick < t0)
+ h->maxtick = t0;
+ h = h->next;
+ } while(h != nil);
+ if(v >= VectorCPIC)
+ io->cisr |= 1<<(v-VectorCPIC);
+ eieio();
+}
+
+int
+intrstats(char *buf, int bsize)
+{
+ Handler *h;
+ int i, n;
+
+ n = 0;
+ for(i=0; i<nelem(halloc.ivec) && n < bsize; i++)
+ if((h = halloc.ivec[i]) != nil && h->nintr)
+ n += snprint(buf+n, bsize-n, "%3d %ud %uld %ud\n", i, h->nintr, h->ticks, h->maxtick);
+ return n;
+}
+
+char*
+fpexcname(Ureg *ur, ulong fpscr, char *buf)
+{
+ int i;
+ char *s;
+ ulong fppc;
+
+ fppc = ur->pc;
+ s = 0;
+ fpscr >>= 3; /* trap enable bits */
+ fpscr &= (fpscr>>22); /* anded with exceptions */
+ for(i=0; i<5; i++)
+ if(fpscr & (1<<i))
+ s = fpcause[i];
+ if(s == 0)
+ return "no floating point exception";
+ sprint(buf, "%s fppc=0x%lux", s, fppc);
+ return buf;
+}
+
+#define KERNPC(x) (KTZERO<(ulong)(x)&&(ulong)(x)<(ulong)etext)
+
+void
+kernfault(Ureg *ur, int code)
+{
+ Label l;
+
+ print("panic: kfault %s dar=0x%lux\n", excname[code], getdar());
+ print("u=0x%lux status=0x%lux pc=0x%lux sp=0x%lux\n",
+ up, ur->status, ur->pc, ur->sp);
+ dumpregs(ur);
+ l.sp = ur->sp;
+ l.pc = ur->pc;
+ dumpstack();
+ for(;;)
+ sched();
+}
+
+void
+dumpstack(void)
+{
+ ulong l, v;
+ int i;
+
+ if(up == 0)
+ return;
+ i = 0;
+ for(l=(ulong)&l; l<(ulong)(up->kstack+KSTACK); l+=4){
+ v = *(ulong*)l;
+ if(KTZERO < v && v < (ulong)etext){
+ print("%lux=%lux, ", l, v);
+ if(i++ == 4){
+ print("\n");
+ i = 0;
+ }
+ }
+ }
+}
+
+void
+dumpregs(Ureg *ur)
+{
+ int i;
+ ulong *l;
+ if(up) {
+ print("registers for %s %ld\n", up->text, up->pid);
+ if(ur->srr1 & MSR_PR == 0)
+ if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK)
+ print("invalid stack ptr\n");
+ }
+ else
+ print("registers for kernel\n");
+
+ print("dsisr\t%.8lux\tdar\t%.8lux\n", getdsisr(), getdar());
+ l = &ur->cause;
+ for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
+ print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
+}
+
+static void
+linkproc(void)
+{
+//print("linkproc %ulx\n", up);
+ spllo();
+ (*up->kpfun)(up->kparg);
+ pexit("", 0);
+}
+
+void
+kprocchild(Proc *p, void (*func)(void*), void *arg)
+{
+ p->sched.pc = (ulong)linkproc;
+ p->sched.sp = (ulong)p->kstack+KSTACK;
+
+ p->kpfun = func;
+ p->kparg = arg;
+}
+
+int
+isvalid_pc(ulong pc)
+{
+ return KERNPC(pc) && (pc&3) == 0;
+}
+
+void
+dumplongs(char*, ulong*, int)
+{
+}
+
+void
+reset(void)
+{
+ IMM *io;
+
+ io = m->iomem;
+ io->plprcrk = KEEP_ALIVE_KEY; // unlock
+ io->plprcr |= IBIT(24); // enable checkstop reset
+ putmsr(getmsr() & ~(MSR_ME|MSR_RI));
+predawn = 1;
+print("reset = %ulx\n", getmsr());
+ delay(1000);
+ // cause checkstop -> causes reset
+ *(uchar*)(0xdeadbeef) = 0;
+ *(ulong*)(0) = 0;
+}
+
+/*
+ * called in sysfile.c
+ */
+void
+evenaddr(ulong addr)
+{
+ if(addr & 3){
+ postnote(up, 1, "sys: odd address", NDebug);
+ error(Ebadarg);
+ }
+}
+
+long
+execregs(ulong entry, ulong ssize, ulong nargs)
+{
+ ulong *sp;
+ Ureg *ureg;
+
+ sp = (ulong*)(USTKTOP - ssize);
+ *--sp = nargs;
+
+ ureg = up->dbgreg;
+ ureg->usp = (ulong)sp;
+ ureg->pc = entry;
+ return USTKTOP-BY2WD; /* address of user-level clock */
+}
+
+void
+forkchild(Proc *p, Ureg *ur)
+{
+ Ureg *cur;
+
+ p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
+ p->sched.pc = (ulong)forkret;
+
+ cur = (Ureg*)(p->sched.sp+2*BY2WD);
+ memmove(cur, ur, sizeof(Ureg));
+ cur->r3 = 0;
+
+ /* Things from bottom of syscall we never got to execute */
+ p->psstate = 0;
+ p->insyscall = 0;
+}
+
+ulong
+userpc(void)
+{
+ Ureg *ureg;
+
+ ureg = (Ureg*)up->dbgreg;
+ return ureg->pc;
+}
+
+
+/* This routine must save the values of registers the user is not
+ * permitted to write from devproc and then restore the saved values
+ * before returning
+ */
+void
+setregisters(Ureg *xp, char *pureg, char *uva, int n)
+{
+ ulong status;
+
+ status = xp->status;
+ memmove(pureg, uva, n);
+ xp->status = status;
+}
+
+/* Give enough context in the ureg to produce a kernel stack for
+ * a sleeping process
+ */
+void
+setkernur(Ureg* ureg, Proc* p)
+{
+ ureg->pc = p->sched.pc;
+ ureg->sp = p->sched.sp+4;
+}
+
+ulong
+dbgpc(Proc *p)
+{
+ Ureg *ureg;
+
+ ureg = p->dbgreg;
+ if(ureg == 0)
+ return 0;
+
+ return ureg->pc;
+}
+
+/*
+ * system calls
+ */
+#include "../port/systab.h"
+
+/*
+ * Syscall should be called directly from assembler without going through trap().
+ */
+void
+syscall(Ureg* ureg)
+{
+ ulong sp;
+ long ret;
+ int i, scallnr;
+
+ if((ureg->srr1 & MSR_PR) == 0)
+ panic("syscall: srr1 0x%4.4uX\n", ureg->srr1);
+
+ m->syscall++;
+ up->insyscall = 1;
+ up->pc = ureg->pc;
+ up->dbgreg = ureg;
+
+ scallnr = ureg->r3;
+//print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
+ up->scallnr = scallnr;
+ spllo();
+
+ sp = ureg->usp;
+ up->nerrlab = 0;
+ ret = -1;
+ if(!waserror()){
+ if(scallnr >= nsyscall){
+ pprint("bad sys call number %d pc %lux\n", scallnr, ureg->pc);
+ postnote(up, 1, "sys: bad sys call", NDebug);
+ error(Ebadarg);
+ }
+
+ if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
+ validaddr(sp, sizeof(Sargs)+BY2WD, 0);
+
+ up->s = *((Sargs*)(sp+BY2WD));
+ up->psstate = sysctab[scallnr];
+
+ ret = systab[scallnr](up->s.args);
+ poperror();
+ }
+ if(up->nerrlab){
+ print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
+ print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
+ for(i = 0; i < NERR; i++)
+ print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
+ panic("error stack");
+ }
+
+ up->insyscall = 0;
+ up->psstate = 0;
+
+ /*
+ * Put return value in frame. On the x86 the syscall is
+ * just another trap and the return value from syscall is
+ * ignored. On other machines the return value is put into
+ * the results register by caller of syscall.
+ */
+ ureg->r3 = ret;
+
+ if(scallnr == NOTED)
+ noted(ureg, *(ulong*)(sp+BY2WD));
+
+ if(scallnr!=RFORK && (up->procctl || up->nnote)){
+ splhi();
+ notify(ureg);
+ }
+}
+/*
+ * Call user, if necessary, with note.
+ * Pass user the Ureg struct and the note on his stack.
+ */
+int
+notify(Ureg* ur)
+{
+ int l;
+ ulong s, sp;
+ Note *n;
+
+ if(up->procctl)
+ procctl(up);
+ if(up->nnote == 0)
+ return 0;
+
+ s = spllo();
+ qlock(&up->debug);
+ up->notepending = 0;
+ n = &up->note[0];
+ if(strncmp(n->msg, "sys:", 4) == 0){
+ l = strlen(n->msg);
+ if(l > ERRLEN-15) /* " pc=0x12345678\0" */
+ l = ERRLEN-15;
+ sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
+ }
+
+ if(n->flag!=NUser && (up->notified || up->notify==0)){
+ if(n->flag == NDebug)
+ pprint("suicide: %s\n", n->msg);
+ qunlock(&up->debug);
+ pexit(n->msg, n->flag!=NDebug);
+ }
+
+ if(up->notified) {
+ qunlock(&up->debug);
+ splhi();
+ return 0;
+ }
+
+ if(!up->notify) {
+ qunlock(&up->debug);
+ pexit(n->msg, n->flag!=NDebug);
+ }
+ sp = ur->usp & ~(BY2V-1);
+ sp -= sizeof(Ureg);
+
+ if(!okaddr((ulong)up->notify, BY2WD, 0) ||
+ !okaddr(sp-ERRLEN-4*BY2WD, sizeof(Ureg)+ERRLEN+4*BY2WD, 1)) {
+ pprint("suicide: bad address or sp in notify\n");
+ qunlock(&up->debug);
+ pexit("Suicide", 0);
+ }
+
+ memmove((Ureg*)sp, ur, sizeof(Ureg));
+ *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
+ up->ureg = (void*)sp;
+ sp -= BY2WD+ERRLEN;
+ memmove((char*)sp, up->note[0].msg, ERRLEN);
+ sp -= 3*BY2WD;
+ *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */
+ ur->r1 = (long)up->ureg; /* arg 1 is ureg* */
+ ((ulong*)sp)[1] = (ulong)up->ureg; /* arg 1 0(FP) is ureg* */
+ ((ulong*)sp)[0] = 0; /* arg 0 is pc */
+ ur->usp = sp;
+ ur->pc = (ulong)up->notify;
+ up->notified = 1;
+ up->nnote--;
+ memmove(&up->lastnote, &up->note[0], sizeof(Note));
+ memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
+
+ qunlock(&up->debug);
+ splx(s);
+ return 1;
+}
+
+
+/*
+ * Return user to state before notify()
+ */
+void
+noted(Ureg* ureg, ulong arg0)
+{
+ Ureg *nureg;
+ ulong oureg, sp;
+
+ qlock(&up->debug);
+ if(arg0!=NRSTR && !up->notified) {
+ qunlock(&up->debug);
+ pprint("call to noted() when not notified\n");
+ pexit("Suicide", 0);
+ }
+ up->notified = 0;
+
+ nureg = up->ureg; /* pointer to user returned Ureg struct */
+
+ /* sanity clause */
+ oureg = (ulong)nureg;
+ if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
+ pprint("bad ureg in noted or call to noted when not notified\n");
+ qunlock(&up->debug);
+ pexit("Suicide", 0);
+ }
+
+ memmove(ureg, nureg, sizeof(Ureg));
+
+ switch(arg0){
+ case NCONT:
+ case NRSTR:
+ if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
+ pprint("suicide: trap in noted\n");
+ qunlock(&up->debug);
+ pexit("Suicide", 0);
+ }
+ up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
+ qunlock(&up->debug);
+ break;
+
+ case NSAVE:
+ if(!okaddr(nureg->pc, BY2WD, 0)
+ || !okaddr(nureg->usp, BY2WD, 0)){
+ pprint("suicide: trap in noted\n");
+ qunlock(&up->debug);
+ pexit("Suicide", 0);
+ }
+ qunlock(&up->debug);
+ sp = oureg-4*BY2WD-ERRLEN;
+ splhi();
+ ureg->sp = sp;
+ ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
+ ((ulong*)sp)[0] = 0; /* arg 0 is pc */
+ break;
+
+ default:
+ pprint("unknown noted arg 0x%lux\n", arg0);
+ up->lastnote.flag = NDebug;
+ /* fall through */
+
+ case NDFLT:
+ if(up->lastnote.flag == NDebug)
+ pprint("suicide: %s\n", up->lastnote.msg);
+ qunlock(&up->debug);
+ pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
+ }
+}
A mtx/uarti8250.c => mtx/uarti8250.c +648 -0
@@ 0,0 1,648 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+/*
+ * 8250 UART and compatibles.
+ */
+enum {
+ Uart0 = 0x3F8, /* COM1 */
+ Uart0IRQ = 4,
+ Uart1 = 0x2F8, /* COM2 */
+ Uart1IRQ = 3,
+
+ UartFREQ = 1843200,
+};
+
+enum { /* I/O ports */
+ Rbr = 0, /* Receiver Buffer (RO) */
+ Thr = 0, /* Transmitter Holding (WO) */
+ Ier = 1, /* Interrupt Enable */
+ Iir = 2, /* Interrupt Identification (RO) */
+ Fcr = 2, /* FIFO Control (WO) */
+ Lcr = 3, /* Line Control */
+ Mcr = 4, /* Modem Control */
+ Lsr = 5, /* Line Status */
+ Msr = 6, /* Modem Status */
+ Scr = 7, /* Scratch Pad */
+ Dll = 0, /* Divisor Latch LSB */
+ Dlm = 1, /* Divisor Latch MSB */
+};
+
+enum { /* Ier */
+ Erda = 0x01, /* Enable Received Data Available */
+ Ethre = 0x02, /* Enable Thr Empty */
+ Erls = 0x04, /* Enable Receiver Line Status */
+ Ems = 0x08, /* Enable Modem Status */
+};
+
+enum { /* Iir */
+ Ims = 0x00, /* Ms interrupt */
+ Ip = 0x01, /* Interrupt Pending (not) */
+ Ithre = 0x02, /* Thr Empty */
+ Irda = 0x04, /* Received Data Available */
+ Irls = 0x06, /* Receiver Line Status */
+ Ictoi = 0x0C, /* Character Time-out Indication */
+ IirMASK = 0x3F,
+ Ife = 0xC0, /* FIFOs enabled */
+};
+
+enum { /* Fcr */
+ FIFOena = 0x01, /* FIFO enable */
+ FIFOrclr = 0x02, /* clear Rx FIFO */
+ FIFOtclr = 0x04, /* clear Tx FIFO */
+ FIFO1 = 0x00, /* Rx FIFO trigger level 1 byte */
+ FIFO4 = 0x40, /* 4 bytes */
+ FIFO8 = 0x80, /* 8 bytes */
+ FIFO14 = 0xC0, /* 14 bytes */
+};
+
+enum { /* Lcr */
+ Wls5 = 0x00, /* Word Length Select 5 bits/byte */
+ Wls6 = 0x01, /* 6 bits/byte */
+ Wls7 = 0x02, /* 7 bits/byte */
+ Wls8 = 0x03, /* 8 bits/byte */
+ WlsMASK = 0x03,
+ Stb = 0x04, /* 2 stop bits */
+ Pen = 0x08, /* Parity Enable */
+ Eps = 0x10, /* Even Parity Select */
+ Stp = 0x20, /* Stick Parity */
+ Brk = 0x40, /* Break */
+ Dlab = 0x80, /* Divisor Latch Access Bit */
+};
+
+enum { /* Mcr */
+ Dtr = 0x01, /* Data Terminal Ready */
+ Rts = 0x02, /* Ready To Send */
+ Out1 = 0x04, /* no longer in use */
+ Ie = 0x08, /* IRQ Enable */
+ Dm = 0x10, /* Diagnostic Mode loopback */
+};
+
+enum { /* Lsr */
+ Dr = 0x01, /* Data Ready */
+ Oe = 0x02, /* Overrun Error */
+ Pe = 0x04, /* Parity Error */
+ Fe = 0x08, /* Framing Error */
+ Bi = 0x10, /* Break Interrupt */
+ Thre = 0x20, /* Thr Empty */
+ Temt = 0x40, /* Tramsmitter Empty */
+ FIFOerr = 0x80, /* error in receiver FIFO */
+};
+
+enum { /* Msr */
+ Dcts = 0x01, /* Delta Cts */
+ Ddsr = 0x02, /* Delta Dsr */
+ Teri = 0x04, /* Trailing Edge of Ri */
+ Ddcd = 0x08, /* Delta Dcd */
+ Cts = 0x10, /* Clear To Send */
+ Dsr = 0x20, /* Data Set Ready */
+ Ri = 0x40, /* Ring Indicator */
+ Dcd = 0x80, /* Data Set Ready */
+};
+
+typedef struct Ctlr {
+ int io;
+ int irq;
+ int tbdf;
+ int iena;
+
+ uchar sticky[8];
+
+ Lock;
+ int fifo;
+ int fena;
+} Ctlr;
+
+extern PhysUart i8250physuart;
+
+static Ctlr i8250ctlr[2] = {
+{ .io = Uart0,
+ .irq = Uart0IRQ,
+ .tbdf = BUSUNKNOWN, },
+
+{ .io = Uart1,
+ .irq = Uart1IRQ,
+ .tbdf = BUSUNKNOWN, },
+};
+
+static Uart i8250uart[2] = {
+{ .regs = &i8250ctlr[0],
+ .name = "COM1",
+ .freq = UartFREQ,
+ .phys = &i8250physuart,
+ .special=0,
+ .next = &i8250uart[1], },
+
+{ .regs = &i8250ctlr[1],
+ .name = "COM2",
+ .freq = UartFREQ,
+ .phys = &i8250physuart,
+ .special=0,
+ .next = nil, },
+};
+
+static Uart* consuart;
+
+#define csr8r(c, r) inb((c)->io+(r))
+#define csr8w(c, r, v) outb((c)->io+(r), (c)->sticky[(r)]|(v))
+
+static long
+i8250status(Uart* uart, void* buf, long n, long offset)
+{
+ char *p;
+ Ctlr *ctlr;
+ uchar ier, lcr, mcr, msr;
+
+ ctlr = uart->regs;
+ p = malloc(READSTR);
+ mcr = ctlr->sticky[Mcr];
+ msr = csr8r(ctlr, Msr);
+ ier = ctlr->sticky[Ier];
+ lcr = ctlr->sticky[Lcr];
+ snprint(p, READSTR,
+ "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",
+
+ uart->baud,
+ uart->hup_dcd,
+ (msr & Dsr) != 0,
+ uart->hup_dsr,
+ (lcr & WlsMASK) + 5,
+ (ier & Ems) != 0,
+ (lcr & Pen) ? ((lcr & Eps) ? 'e': 'o'): 'n',
+ (mcr & Rts) != 0,
+ (lcr & Stb) ? 2: 1,
+ ctlr->fena,
+
+ uart->dev,
+ uart->type,
+ uart->ferr,
+ uart->oerr,
+ (msr & Cts) ? " cts": "",
+ (msr & Dsr) ? " dsr": "",
+ (msr & Dcd) ? " dcd": "",
+ (msr & Ri) ? " ring": ""
+ );
+ n = readstr(offset, buf, n, p);
+ free(p);
+
+ return n;
+}
+
+static void
+i8250fifo(Uart* uart, int on)
+{
+ int i;
+ Ctlr *ctlr;
+
+ /*
+ * Toggle FIFOs:
+ * if none, do nothing;
+ * reset the Rx and Tx FIFOs;
+ * empty the Rx buffer and clear any interrupt conditions;
+ * if enabling, try to turn them on.
+ */
+ ctlr = uart->regs;
+
+ ilock(ctlr);
+ if(!ctlr->fifo){
+ csr8w(ctlr, Fcr, FIFOtclr|FIFOrclr);
+ for(i = 0; i < 16; i++){
+ csr8r(ctlr, Iir);
+ csr8r(ctlr, Rbr);
+ }
+
+ ctlr->fena = 0;
+ if(on){
+ csr8w(ctlr, Fcr, FIFO4|FIFOena);
+ if(!(csr8r(ctlr, Iir) & Ife))
+ ctlr->fifo = 1;
+ ctlr->fena = 1;
+ }
+ }
+ iunlock(ctlr);
+}
+
+static void
+i8250dtr(Uart* uart, int on)
+{
+ Ctlr *ctlr;
+
+ /*
+ * Toggle DTR.
+ */
+ ctlr = uart->regs;
+ if(on)
+ ctlr->sticky[Mcr] |= Dtr;
+ else
+ ctlr->sticky[Mcr] &= ~Dtr;
+ csr8w(ctlr, Mcr, 0);
+}
+
+static void
+i8250rts(Uart* uart, int on)
+{
+ Ctlr *ctlr;
+
+ /*
+ * Toggle RTS.
+ */
+ ctlr = uart->regs;
+ if(on)
+ ctlr->sticky[Mcr] |= Rts;
+ else
+ ctlr->sticky[Mcr] &= ~Rts;
+ csr8w(ctlr, Mcr, 0);
+}
+
+static void
+i8250modemctl(Uart* uart, int on)
+{
+ Ctlr *ctlr;
+
+ ctlr = uart->regs;
+ ilock(&uart->tlock);
+ if(on){
+ ctlr->sticky[Ier] |= Ems;
+ csr8w(ctlr, Ier, 0);
+ uart->modem = 1;
+ uart->cts = csr8r(ctlr, Msr) & Cts;
+ }
+ else{
+ ctlr->sticky[Ier] &= ~Ems;
+ csr8w(ctlr, Ier, 0);
+ uart->modem = 0;
+ uart->cts = 1;
+ }
+ iunlock(&uart->tlock);
+
+ /* modem needs fifo */
+ (*uart->phys->fifo)(uart, on);
+}
+
+static int
+i8250parity(Uart* uart, int parity)
+{
+ int lcr;
+ Ctlr *ctlr;
+
+ ctlr = uart->regs;
+ lcr = ctlr->sticky[Lcr] & ~(Eps|Pen);
+
+ switch(parity){
+ case 'e':
+ lcr |= Eps|Pen;
+ break;
+ case 'o':
+ lcr |= Pen;
+ break;
+ case 'n':
+ default:
+ break;
+ }
+ ctlr->sticky[Lcr] = lcr;
+ csr8w(ctlr, Lcr, 0);
+
+ uart->parity = parity;
+
+ return 0;
+}
+
+static int
+i8250stop(Uart* uart, int stop)
+{
+ int lcr;
+ Ctlr *ctlr;
+
+ ctlr = uart->regs;
+ lcr = ctlr->sticky[Lcr] & ~Stb;
+
+ switch(stop){
+ case 1:
+ break;
+ case 2:
+ lcr |= Stb;
+ break;
+ default:
+ return -1;
+ }
+ ctlr->sticky[Lcr] = lcr;
+ csr8w(ctlr, Lcr, 0);
+
+ uart->stop = stop;
+
+ return 0;
+}
+
+static int
+i8250bits(Uart* uart, int bits)
+{
+ int lcr;
+ Ctlr *ctlr;
+
+ ctlr = uart->regs;
+ lcr = ctlr->sticky[Lcr] & ~WlsMASK;
+
+ switch(bits){
+ case 5:
+ lcr |= Wls5;
+ break;
+ case 6:
+ lcr |= Wls6;
+ break;
+ case 7:
+ lcr |= Wls7;
+ break;
+ case 8:
+ lcr |= Wls8;
+ break;
+ default:
+ return -1;
+ }
+ ctlr->sticky[Lcr] = lcr;
+ csr8w(ctlr, Lcr, 0);
+
+ uart->bits = bits;
+
+ return 0;
+}
+
+static int
+i8250baud(Uart* uart, int baud)
+{
+ ulong bgc;
+ Ctlr *ctlr;
+
+ /*
+ * Set the Baud rate by calculating and setting the Baud rate
+ * Generator Constant. This will work with fairly non-standard
+ * Baud rates.
+ */
+ if(uart->freq == 0 || baud <= 0)
+ return -1;
+ bgc = (uart->freq+8*baud-1)/(16*baud);
+
+ ctlr = uart->regs;
+ csr8w(ctlr, Lcr, Dlab);
+ outb(ctlr->io+Dlm, bgc>>8);
+ outb(ctlr->io+Dll, bgc);
+ csr8w(ctlr, Lcr, 0);
+
+ uart->baud = baud;
+
+ return 0;
+}
+
+static void
+i8250break(Uart* uart, int ms)
+{
+ Ctlr *ctlr;
+
+ /*
+ * Send a break.
+ */
+ if(ms == 0)
+ ms = 200;
+
+ ctlr = uart->regs;
+ csr8w(ctlr, Lcr, Brk);
+ tsleep(&up->sleep, return0, 0, ms);
+ csr8w(ctlr, Lcr, 0);
+}
+
+static void
+i8250kick(Uart* uart)
+{
+ int i;
+ Ctlr *ctlr;
+
+ if(uart->cts == 0 || uart->blocked)
+ return;
+
+ /*
+ * 128 here is an arbitrary limit to make sure
+ * we don't stay in this loop too long. If the
+ * chip's output queue is longer than 128, too
+ * bad -- presotto
+ */
+ ctlr = uart->regs;
+ for(i = 0; i < 128; i++){
+ if(!(csr8r(ctlr, Lsr) & Thre))
+ break;
+ if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
+ break;
+ outb(ctlr->io+Thr, *(uart->op++));
+ }
+}
+
+static void
+i8250interrupt(Ureg*, void* arg)
+{
+ Ctlr *ctlr;
+ Uart *uart;
+ int iir, lsr, old, r;
+
+ uart = arg;
+
+ ctlr = uart->regs;
+ for(iir = csr8r(ctlr, Iir); !(iir & Ip); iir = csr8r(ctlr, Iir)){
+ switch(iir & IirMASK){
+ case Ims: /* Ms interrupt */
+ r = csr8r(ctlr, Msr);
+ if(r & Dcts){
+ ilock(&uart->tlock);
+ old = uart->cts;
+ uart->cts = r & Cts;
+ if(old == 0 && uart->cts)
+ uart->ctsbackoff = 2;
+ iunlock(&uart->tlock);
+ }
+ if(r & Ddsr){
+ old = r & Dsr;
+ if(uart->hup_dsr && uart->dsr && !old)
+ uart->dohup = 1;
+ uart->dsr = old;
+ }
+ if(r & Ddcd){
+ old = r & Dcd;
+ if(uart->hup_dcd && uart->dcd && !old)
+ uart->dohup = 1;
+ uart->dcd = old;
+ }
+ break;
+ case Ithre: /* Thr Empty */
+ uartkick(uart);
+ break;
+ case Irda: /* Received Data Available */
+ case Ictoi: /* Character Time-out Indication */
+ /*
+ * Consume any received data.
+ * If the received byte came in with a break,
+ * parity or framing error, throw it away;
+ * overrun is an indication that something has
+ * already been tossed.
+ */
+ while((lsr = csr8r(ctlr, Lsr)) & Dr){
+ if(lsr & Oe)
+ uart->oerr++;
+ if(lsr & Pe)
+ uart->perr++;
+ if(lsr & Fe)
+ uart->ferr++;
+ r = csr8r(ctlr, Rbr);
+ if(!(lsr & (Bi|Fe|Pe)))
+ uartrecv(uart, r);
+ }
+ break;
+ default:
+ iprint("weird uart interrupt 0x%2.2uX\n", iir);
+ break;
+ }
+ }
+}
+
+static void
+i8250disable(Uart* uart)
+{
+ Ctlr *ctlr;
+
+ /*
+ * Turn off DTR and RTS, disable interrupts and fifos.
+ */
+ (*uart->phys->dtr)(uart, 0);
+ (*uart->phys->rts)(uart, 0);
+ (*uart->phys->fifo)(uart, 0);
+
+ ctlr = uart->regs;
+ ctlr->sticky[Ier] = 0;
+ csr8w(ctlr, Ier, 0);
+}
+
+static void
+i8250enable(Uart* uart, int ie)
+{
+ Ctlr *ctlr;
+
+ /*
+ * Enable interrupts and turn on DTR and RTS.
+ * Be careful if this is called to set up a polled serial line
+ * early on not to try to enable interrupts as interrupt-
+ * -enabling mechanisms might not be set up yet.
+ */
+ ctlr = uart->regs;
+ if(ie){
+ if(ctlr->iena == 0){
+ intrenable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name);
+ ctlr->iena = 1;
+ }
+ ctlr->sticky[Ier] = Ethre|Erda;
+ ctlr->sticky[Mcr] |= Ie;
+ }
+ else{
+ ctlr->sticky[Ier] = 0;
+ ctlr->sticky[Mcr] = 0;
+ }
+ csr8w(ctlr, Ier, ctlr->sticky[Ier]);
+ csr8w(ctlr, Mcr, ctlr->sticky[Mcr]);
+
+ (*uart->phys->dtr)(uart, 1);
+ (*uart->phys->rts)(uart, 1);
+}
+
+static Uart*
+i8250pnp(void)
+{
+ return i8250uart;
+}
+
+PhysUart i8250physuart = {
+ .name = "i8250",
+ .pnp = i8250pnp,
+ .enable = i8250enable,
+ .disable = i8250disable,
+ .kick = i8250kick,
+ .dobreak = i8250break,
+ .baud = i8250baud,
+ .bits = i8250bits,
+ .stop = i8250stop,
+ .parity = i8250parity,
+ .modemctl = i8250modemctl,
+ .rts = i8250rts,
+ .dtr = i8250dtr,
+ .status = i8250status,
+ .fifo = i8250fifo,
+};
+
+int
+serialgetc(void)
+{
+ return -1;
+}
+
+static void
+i8250putc(Ctlr* ctlr, int c)
+{
+ int i;
+
+ for(i = 0; i < 128; i++){
+ if(csr8r(ctlr, Lsr) & Thre)
+ break;
+ delay(1);
+ }
+ outb(ctlr->io+Thr, c);
+}
+
+static void
+i8250puts(char* s, int n)
+{
+ Ctlr *ctlr;
+ Uart *uart;
+
+ if((uart = consuart) == nil)
+ return;
+
+ ctlr = uart->regs;
+ while(n--){
+ if(*s == '\n')
+ i8250putc(ctlr, '\r');
+ i8250putc(ctlr, *s++);
+ }
+}
+
+void
+i8250console(void)
+{
+ Uart *uart;
+ int n;
+ char *cmd, *p;
+
+ if((p = getconf("console")) == nil)
+ return;
+ n = strtoul(p, &cmd, 0);
+ if(p == cmd)
+ return;
+ switch(n){
+ default:
+ return;
+ case 0:
+ uart = &i8250uart[0];
+ break;
+ case 1:
+ uart = &i8250uart[1];
+ break;
+ }
+
+ if(*cmd == 0)
+ cmd = "b9600 l8 pn s1";
+ uartctl(uart, cmd);
+ (*uart->phys->enable)(uart, 0);
+
+ consuart = uart;
+ serialputs = i8250puts;
+ uart->console = 1;
+}