diff options
Diffstat (limited to 'os/cerf1110')
| -rwxr-xr-x | os/cerf1110/Mk | 8 | ||||
| -rw-r--r-- | os/cerf1110/NOTICE | 2 | ||||
| -rw-r--r-- | os/cerf1110/README | 22 | ||||
| -rw-r--r-- | os/cerf1110/archcerf.c | 177 | ||||
| -rw-r--r-- | os/cerf1110/cerf | 159 | ||||
| -rw-r--r-- | os/cerf1110/dat.h | 135 | ||||
| -rw-r--r-- | os/cerf1110/devata.c | 1200 | ||||
| -rw-r--r-- | os/cerf1110/devcerf.c | 128 | ||||
| -rw-r--r-- | os/cerf1110/ether8900.c | 702 | ||||
| -rw-r--r-- | os/cerf1110/fns.h | 179 | ||||
| -rw-r--r-- | os/cerf1110/io.h | 1 | ||||
| -rw-r--r-- | os/cerf1110/main.c | 255 | ||||
| -rw-r--r-- | os/cerf1110/mem.h | 200 | ||||
| -rw-r--r-- | os/cerf1110/mkfile | 101 |
14 files changed, 3269 insertions, 0 deletions
diff --git a/os/cerf1110/Mk b/os/cerf1110/Mk new file mode 100755 index 00000000..51d69a44 --- /dev/null +++ b/os/cerf1110/Mk @@ -0,0 +1,8 @@ +#!/bin/rc +rfork ne +ROOT=/usr/inferno +fn cd +NPROC=3 +path=(/usr/inferno/Plan9/$cputype/bin $path) +#bind /usr/inferno/mkconfig.dist /usr/inferno/mkconfig +exec mk $* diff --git a/os/cerf1110/NOTICE b/os/cerf1110/NOTICE new file mode 100644 index 00000000..537233a4 --- /dev/null +++ b/os/cerf1110/NOTICE @@ -0,0 +1,2 @@ +Inferno® Copyright © 1996-1999 Lucent Technologies Inc. All rights reserved. +Cerfcube 1110 Inferno port Copyright © 2000,2003 Vita Nuova Holdings Limited. All rights reserved. diff --git a/os/cerf1110/README b/os/cerf1110/README new file mode 100644 index 00000000..5354030c --- /dev/null +++ b/os/cerf1110/README @@ -0,0 +1,22 @@ +Booting Inferno on a Cerf cube + +Build the /usr/inferno/os/cerf1110 kernel into /usr/inferno/os/cerf1110/icerf: + mk +It uses common SA1110 code in ../sa1110, as well as ../port etc. + +Make that icerf file available to the cerf cube by tftp. How you do that depends on +your host system. + +It should then be easy: + +1. Reset the cerf cube (power off/on), and quickly, during `Waiting for RTC to stabilize' + hit a key. + +2. type + tftp /usr/inferno/os/cerf1110/icerf c0008000 + with appropriate substitution for file name. + +3. on success + boot c0008000 0 0 + +it should run. diff --git a/os/cerf1110/archcerf.c b/os/cerf1110/archcerf.c new file mode 100644 index 00000000..86eb902e --- /dev/null +++ b/os/cerf1110/archcerf.c @@ -0,0 +1,177 @@ +/* + * Intrinsyc Cerf cube + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "io.h" +#include "draw.h" +#include <memdraw.h> + +#include "../port/netif.h" +#include "etherif.h" +#include "../port/flashif.h" + +enum { + /* Cerf GPIO assignment */ + LED0 = 1<<0, /* active high */ + LED1 = 1<<1, + LED2 = 1<<2, + LED3 = 1<<3, + /* 4 to 15 appear on J2 */ + CFBVD1 = 1<<20, + CFBVD2 = 1<<19, + CFReset = 1<<21, /* active low for IDE mode; active high for IO or memory mode */ + CFRdypin = 22, + CFRdy = 1<<CFRdypin, /* RDY/nBSY */ + CFnCDxpin = 23, + CFnCDx = 1<<CFnCDxpin, /* low => card inserted */ + EnableRS232In = 1<<24, + EnableRS232Out = 1<<25, + /* CS8900 interrupt on 26, active high */ + /* CS8900 nHWSLEEP on 27 */ +}; + +void +archreset(void) +{ + GpioReg *g = GPIOREG; + + g->grer = 0; + g->gfer = 0; + g->gedr = g->gedr; + g->gpdr = 0; + + g->gpdr = EnableRS232In | EnableRS232Out | CFReset; + g->gpsr = EnableRS232In | EnableRS232Out; + + GPCLKREG->gpclkr0 |= 1; /* SUS=1 for uart on serial 1 */ +} + +void +archconfinit(void) +{ + int w; + + conf.topofmem = 0xC0000000+32*MB; + w = PMGRREG->ppcr & 0x1f; + m->cpuhz = CLOCKFREQ*(w*4+16); + + conf.useminicache = 1; + conf.portrait = 1; /* should take from param flash or allow dynamic change */ +} + +void +archconsole(void) +{ + uartspecial(0, 38400, 'n', &kbdq, &printq, kbdcr2nl); +} + +void +archuartpower(int, int) +{ +} + +void +kbdinit(void) +{ +} + +void +archreboot(void) +{ + dcflushall(); + GPIOREG->gedr = 1<<0; + mmuputctl(mmugetctl() & ~CpCaltivec); /* restore bootstrap's vectors */ + RESETREG->rsrr = 1; /* software reset */ + for(;;) + spllo(); +} + +void +archflashwp(Flash*, int) +{ +} + +/* + * for devflash.c:/^flashreset + * retrieve flash type, virtual base and length and return 0; + * return -1 on error (no flash) + */ +int +archflashreset(int bank, Flash *f) +{ + if(bank != 0) + return -1; + f->type = "cfi16"; + f->addr = KADDR(FLASHMEM); + f->size = 0; + f->width = 2; + return 0; +} + +/* + * pcmcia + */ +int +pcmpowered(int slotno) +{ + if(slotno) + return 0; + return 3; +} + +void +pcmpower(int slotno, int on) +{ + USED(slotno, on); +} + +void +pcmreset(int slot) +{ + if(slot != 0) + return; + GPIOREG->gpsr = CFReset; + delay(100); + GPIOREG->gpcr = CFReset; +} + +int +pcmpin(int slot, int type) +{ + if(slot) + return -1; + switch(type){ + case PCMready: + return CFRdypin; + case PCMeject: + return CFnCDxpin; + case PCMstschng: + return -1; + } +} + +void +pcmsetvpp(int slot, int vpp) +{ + USED(slot, vpp); +} + +/* + * set ether parameters: the contents should be derived from EEPROM or NVRAM + */ +int +archether(int ctlno, Ether *ether) +{ + if(ctlno > 0) + return -1; + sprint(ether->type, "CS8900"); + ether->nopt = 0; + ether->irq = 26; /* GPIO */ + ether->itype = BusGPIOrising; + return 1; +} diff --git a/os/cerf1110/cerf b/os/cerf1110/cerf new file mode 100644 index 00000000..24002405 --- /dev/null +++ b/os/cerf1110/cerf @@ -0,0 +1,159 @@ +dev + root + cons archcerf + env + gpio + mnt + pipe + prog + rtc + srv + dup + ssl + cap + sign +# draw screen +# pointer + uart + ip bootp ip ipv6 ipaux iproute arp netlog ptclbsum iprouter plan9 nullmedium pktmedium netaux + flash + ftl + pcmcia cis + ata + ether netif netaux ethermedium + + cerf +# kprof + +ip + il + tcp + udp +# rudp +# igmp + ipifc + icmp + icmp6 +# ipmux + +link + flashcfi16 + ether8900 + +lib + interp +# tk +# draw +# memlayer +# memdraw + keyring + sec + mp + math + kern + +mod + math + sys +# draw +# tk + keyring + +port + alarm + alloc + allocb + chan + dev + dial + dis + discall + exception + exportfs + inferno + latin1 + nocache + nodynld + parse + pgrp + print + proc + qio + qlock + random + sysfile + taslock + xalloc + +code + int kernel_pool_pcnt = 10; + int main_pool_pcnt = 40; + int heap_pool_pcnt = 40; + int image_pool_pcnt = 0; + int cflag = 0; /* for JIT */ + + int consoleprint = 1; + int redirectconsole = 1; + char debug_keys = 1; + int panicreset = 0; + void screeninit(void){} + +init + cerfinit + +root + /chan / + /dev / + /dis + /env / + /fd / + /net / + /net.alt / + /nvfs / + /prog / + /dis/lib + /dis/disk + /osinit.dis + +# dos file system + /dis/dossrv.dis + /dis/lib/arg.dis + /dis/lib/styx.dis + /dis/lib/string.dis + /dis/lib/daytime.dis + + /dis/disk/format.dis + +# For development work: + /dis/sh.dis /dis/tiny/sh.dis + /dis/ls.dis + /dis/cat.dis + /dis/bind.dis + /dis/mount.dis + /dis/pwd.dis + /dis/echo.dis + /dis/cd.dis + /dis/xd.dis + /dis/cp.dis + /dis/mkdir.dis + /dis/rm.dis + /dis/p.dis + /dis/ps.dis + /dis/lib/readdir.dis + /dis/lib/workdir.dis + /dis/lib/daytime.dis + /dis/lib/auth.dis + /dis/lib/ssl.dis + /dis/lib/bufio.dis + /dis/lib/string.dis +# /dis/pcmcia.dis /usr/forsyth/pcmcia.dis + + /n/remote + /n/local + /n/client + /n/rdbg + /n/dump + /n/disk + /n/kfs +# Authentication + /nvfs/default /usr/inferno/keyring/default diff --git a/os/cerf1110/dat.h b/os/cerf1110/dat.h new file mode 100644 index 00000000..553c0cb0 --- /dev/null +++ b/os/cerf1110/dat.h @@ -0,0 +1,135 @@ +typedef struct Conf Conf; +typedef struct Dma Dma; +typedef struct FPU FPU; +typedef struct FPenv FPenv; +typedef struct Label Label; +typedef struct Lock Lock; +typedef struct Mach Mach; +typedef struct Ureg Ureg; +typedef struct ISAConf ISAConf; +typedef struct PCMmap PCMmap; +typedef struct PCMslot PCMslot; + +typedef ulong Instr; + +struct Conf +{ + ulong nmach; /* processors */ + ulong nproc; /* processes */ + ulong npage0; /* total physical pages of memory */ + ulong npage1; /* total physical pages of memory */ + ulong topofmem; /* highest physical address + 1 */ + ulong npage; /* total physical pages of memory */ + ulong base0; /* base of bank 0 */ + ulong base1; /* base of bank 1 */ + ulong ialloc; /* max interrupt time allocation in bytes */ + + int useminicache; /* use mini cache: screen.c/lcd.c */ + int textwrite; /* writeable text segment, for debug */ + int portrait; /* display orientation */ +}; + +#define NISAOPT 8 +struct ISAConf { + char type[KNAMELEN]; + ulong port; + ulong irq; + int itype; + ulong dma; + ulong mem; + ulong size; + ulong freq; + + int nopt; + char *opt[NISAOPT]; +}; + +/* + * FPenv.status + */ +enum +{ + FPINIT, + FPACTIVE, + FPINACTIVE, +}; + +struct FPenv +{ + ulong status; + ulong control; + ushort fpistate; /* emulated fp */ + ulong regs[8][3]; /* emulated fp */ +}; + +/* + * This structure must agree with fpsave and fprestore asm routines + */ +struct FPU +{ + FPenv env; +}; + +struct Label +{ + ulong sp; + ulong pc; +}; + +struct Lock +{ + ulong key; + ulong sr; + ulong pc; + int pri; +}; + +#include "../port/portdat.h" + +/* + * machine dependent definitions not used by ../port/portdat.h + */ +struct Mach +{ + /* OFFSETS OF THE FOLLOWING KNOWN BY l.s */ + ulong splpc; /* pc of last caller to splhi */ + + /* ordering from here on irrelevant */ + + int machno; /* physical id of processor */ + ulong ticks; /* of the clock since boot time */ + 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 cpuhz; + + /* stacks for exceptions */ + ulong fiqstack[4]; + ulong irqstack[4]; + ulong abtstack[4]; + ulong undstack[4]; + + int stack[1]; +}; + +#define MACHP(n) (n == 0 ? (Mach*)(MACHADDR) : (Mach*)0) + +extern Mach *m; +extern Proc *up; + +typedef struct MemBank { + uint pbase; + uint plimit; + uint vbase; + uint vlimit; +} MemBank; + +/* + * Layout at virtual address 0. + */ +typedef struct Vectorpage { + void (*vectors[8])(void); + uint vtable[8]; +} Vectorpage; +extern Vectorpage *page0; diff --git a/os/cerf1110/devata.c b/os/cerf1110/devata.c new file mode 100644 index 00000000..bca9cda3 --- /dev/null +++ b/os/cerf1110/devata.c @@ -0,0 +1,1200 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#define DPRINT if(0)iprint + +typedef struct Drive Drive; +typedef struct Ident Ident; +typedef struct Controller Controller; +typedef struct Partition Partition; +typedef struct Repl Repl; + +enum +{ + /* ports */ + Pbase= 0x1F0, + Pdata= 0, /* data port (16 bits) */ + Perror= 1, /* error port (read) */ + Pprecomp= 1, /* buffer mode port (write) */ + Pcount= 2, /* sector count port */ + Psector= 3, /* sector number port */ + Pcyllsb= 4, /* least significant byte cylinder # */ + Pcylmsb= 5, /* most significant byte cylinder # */ + Pdh= 6, /* drive/head port */ + Pstatus= 7, /* status port (read) */ + Sbusy= (1<<7), + Sready= (1<<6), + Sdrq= (1<<3), + Serr= (1<<0), + Pcmd= 7, /* cmd port (write) */ + + /* commands */ + Crecal= 0x10, + Cread= 0x20, + Cwrite= 0x30, + Cident= 0xEC, + Cident2= 0xFF, /* pseudo command for post Cident interrupt */ + Csetbuf= 0xEF, + Cinitparam= 0x91, + + /* conner specific commands */ + Cstandby= 0xE2, + Cidle= 0xE1, + Cpowerdown= 0xE3, + + /* disk states */ + Sspinning, + Sstandby, + Sidle, + Spowerdown, + + /* something we have to or into the drive/head reg */ + DHmagic= 0xA0, + + /* file types */ + Qdir= 0, + Qfile, + + Maxxfer= BY2PG, /* maximum transfer size/cmd */ + Npart= 8+2, /* 8 sub partitions, disk, and partition */ + Nrepl= 64, /* maximum replacement blocks */ +}; +#define PART(x) (((x)>>1)&0xF) +#define DRIVE(x) (((x)>>5)&0x7) +#define MKQID(d,p) (((d)<<5) | ((p)<<1) | Qfile) + +struct Partition +{ + ulong start; + ulong end; + char name[KNAMELEN+1]; +}; + +struct Repl +{ + Partition *p; + int nrepl; + ulong blk[Nrepl]; +}; + +#define PARTMAGIC "plan9 partitions" +#define REPLMAGIC "block replacements" + +/* + * an ata drive + */ +struct Drive +{ + QLock; + + Controller *cp; + int drive; + int confused; /* needs to be recalibrated (or worse) */ + int online; + int npart; /* number of real partitions */ + Partition p[Npart]; + Repl repl; + ulong usetime; + int state; + char vol[KNAMELEN]; + + ulong cap; /* total bytes */ + int bytes; /* bytes/sector */ + int sectors; /* sectors/track */ + int heads; /* heads/cyl */ + long cyl; /* cylinders/drive */ + + char lba; /* true if drive has logical block addressing */ + char multi; /* non-zero if drive does multiple block xfers */ +}; + +/* + * a controller for 2 drives + */ +struct Controller +{ + QLock; /* exclusive access to the controller */ + ISAConf; /* interface to pcmspecial */ + + Lock reglock; /* exclusive access to the registers */ + + int confused; /* needs to be recalibrated (or worse) */ + ulong pbase; /* base port (copied from ISAConf) */ + + /* + * current operation + */ + int cmd; /* current command */ + int lastcmd; /* debugging info */ + Rendez r; /* wait here for command termination */ + char *buf; /* xfer buffer */ + int nsecs; /* length of transfer (sectors) */ + int sofar; /* sectors transferred so far */ + int status; + int error; + Drive *dp; /* drive being accessed */ +}; + +Controller *atac; +Drive *ata; +static char* ataerr; +static int nhard; +static int spindowntime; + +static void ataintr(Ureg*, void*); +static long ataxfer(Drive*, Partition*, int, long, long, char*); +static void ataident(Drive*); +static void atasetbuf(Drive*, int); +static void ataparams(Drive*); +static void atapart(Drive*); +static int ataprobe(Drive*, int, int, int); + +static int +atagen(Chan *c, char*, Dirtab*, int, int s, Dir *dirp) +{ + Qid qid; + int drive; + Drive *dp; + Partition *pp; + ulong l; + + if(s == DEVDOTDOT){ + mkqid(&qid, 0, 0, QTDIR); + sprint(up->genbuf, "#%C", devtab[c->type]->dc); + devdir(c, qid, up->genbuf, 0, eve, 0555, dirp); + return 1; + } + qid.vers = 0; + qid.type = QTFILE; + drive = s/Npart; + s = s % Npart; + if(drive >= nhard) + return -1; + dp = &ata[drive]; + + if(dp->online == 0 || s >= dp->npart) + return 0; + + pp = &dp->p[s]; + sprint(up->genbuf, "%s%s", dp->vol, pp->name); + qid.path = MKQID(drive, s); + l = (pp->end - pp->start) * dp->bytes; + devdir(c, qid, up->genbuf, l, eve, 0660, dirp); + return 1; +} + +static void +atainit(void) +{ + Drive *dp; + Controller *cp; + uchar equip; + int pcmslot; + + if (atac) + return; /* already done */ + + equip = 0x10; /* hard coded */ + + cp = malloc(sizeof(*cp)); + if (!cp) + error(Enomem); + + cp->port = Pbase; + cp->irq = 14; + cp->nopt = 1; + cp->opt[0] = "index=1"; + + if((pcmslot = pcmspecial("ATA FLASH", cp)) < 0) { + DPRINT("No ATA card\n"); + free(cp); + ataerr = Enoifc; + return; + } + ata = malloc(2 * sizeof(*ata)); + if(ata == nil) { + pcmspecialclose(pcmslot); + free(cp); + error(Enomem); + } + + atac = cp; + cp->buf = 0; + cp->lastcmd = cp->cmd; + cp->cmd = 0; + cp->pbase = cp->port; + intrenable(cp->irq, ataintr, cp, cp->itype, "ata"); + + dp = ata; + if(equip & 0xf0){ + dp->drive = 0; + dp->online = 0; + dp->cp = cp; + dp++; + } + if((equip & 0x0f)){ + dp->drive = 1; + dp->online = 0; + dp->cp = cp; + dp++; + } + nhard = dp - ata; + + spindowntime = 1; +} + + +/* + * Get the characteristics of each drive. Mark unresponsive ones + * off line. + */ +static Chan* +ataattach(char *spec) +{ + Drive *dp; + + atainit(); + if (!ata) + error(ataerr ? ataerr : Enoifc); + for(dp = ata; dp < &ata[nhard]; dp++){ + if(waserror()){ + dp->online = 0; + qunlock(dp); + continue; + } + qlock(dp); + if(!dp->online){ + /* + * Make sure ataclock() doesn't + * interfere. + */ + dp->usetime = m->ticks; + ataparams(dp); + dp->online = 1; + atasetbuf(dp, 1); + } + + /* + * read Plan 9 partition table + */ + atapart(dp); + qunlock(dp); + poperror(); + } + return devattach('H', spec); +} + +static Walkqid* +atawalk(Chan *c, Chan *nc, char **name, int nname) +{ + return devwalk(c, nc, name, nname, 0, 0, atagen); +} + +static int +atastat(Chan *c, uchar *dp, int n) +{ + return devstat(c, dp, n, 0, 0, atagen); +} + +static Chan* +ataopen(Chan *c, int omode) +{ + return devopen(c, omode, 0, 0, atagen); +} + +static void +ataclose(Chan *c) +{ + Drive *d; + Partition *p; + + if(c->mode != OWRITE && c->mode != ORDWR) + return; + + d = &ata[DRIVE(c->qid.path)]; + p = &d->p[PART(c->qid.path)]; + if(strcmp(p->name, "partition") != 0) + return; + + if(waserror()){ + qunlock(d); + nexterror(); + } + qlock(d); + atapart(d); + qunlock(d); + poperror(); +} + +static long +ataread(Chan *c, void *a, long n, vlong offset) +{ + Drive *dp; + long rv, i; + int skip; + uchar *aa = a; + Partition *pp; + char *buf; + + if(c->qid.type & QTDIR) + return devdirread(c, a, n, 0, 0, atagen); + + buf = smalloc(Maxxfer); + if(waserror()){ + free(buf); + nexterror(); + } + + dp = &ata[DRIVE(c->qid.path)]; + pp = &dp->p[PART(c->qid.path)]; + + skip = offset % dp->bytes; + for(rv = 0; rv < n; rv += i){ + i = ataxfer(dp, pp, Cread, offset+rv-skip, n-rv+skip, buf); + if(i == 0) + break; + i -= skip; + if(i > n - rv) + i = n - rv; + memmove(aa+rv, buf + skip, i); + skip = 0; + } + + free(buf); + poperror(); + + return rv; +} + +static long +atawrite(Chan *c, void *a, long n, vlong offset) +{ + Drive *dp; + long rv, i, partial; + uchar *aa = a; + Partition *pp; + char *buf; + + if(c->qid.type & QTDIR) + error(Eisdir); + + dp = &ata[DRIVE(c->qid.path)]; + pp = &dp->p[PART(c->qid.path)]; + buf = smalloc(Maxxfer); + if(waserror()){ + free(buf); + nexterror(); + } + + /* + * if not starting on a sector boundary, + * read in the first sector before writing + * it out. + */ + partial = offset % dp->bytes; + if(partial){ + ataxfer(dp, pp, Cread, offset-partial, dp->bytes, buf); + if(partial+n > dp->bytes) + rv = dp->bytes - partial; + else + rv = n; + memmove(buf+partial, aa, rv); + ataxfer(dp, pp, Cwrite, offset-partial, dp->bytes, buf); + } else + rv = 0; + + /* + * write out the full sectors + */ + partial = (n - rv) % dp->bytes; + n -= partial; + for(; rv < n; rv += i){ + i = n - rv; + if(i > Maxxfer) + i = Maxxfer; + memmove(buf, aa+rv, i); + i = ataxfer(dp, pp, Cwrite, offset+rv, i, buf); + if(i == 0) + break; + } + + /* + * if not ending on a sector boundary, + * read in the last sector before writing + * it out. + */ + if(partial){ + ataxfer(dp, pp, Cread, offset+rv, dp->bytes, buf); + memmove(buf, aa+rv, partial); + ataxfer(dp, pp, Cwrite, offset+rv, dp->bytes, buf); + rv += partial; + } + + free(buf); + poperror(); + + return rv; +} + +/* + * did an interrupt happen? + */ +static int +cmddone(void *a) +{ + Controller *cp = a; + + return cp->cmd == 0; +} + +/* + * Wait for the controller to be ready to accept a command. + * This is protected from interference by ataclock() by + * setting dp->usetime before it is called. + */ +static void +cmdreadywait(Drive *dp) +{ + long start; + int period; + Controller *cp = dp->cp; + + /* give it 2 seconds to spin down and up */ + if(dp->state == Sspinning) + period = 10; + else + period = 2000; + + start = m->ticks; + while((inb(cp->pbase+Pstatus) & (Sready|Sbusy)) != Sready) + if(TK2MS(m->ticks - start) > period){ + DPRINT("cmdreadywait failed\n"); + error(Eio); + } +} + +static void +atarepl(Drive *dp, long bblk) +{ + int i; + + if(dp->repl.p == 0) + return; + for(i = 0; i < dp->repl.nrepl; i++){ + if(dp->repl.blk[i] == bblk) + DPRINT("found bblk %ld at offset %d\n", bblk, i); + } +} + +static void +atasleep(Controller *cp, int ms) +{ + tsleep(&cp->r, cmddone, cp, ms); + if(cp->cmd && cp->cmd != Cident2){ + DPRINT("ata: cmd 0x%uX timeout, status=%ux\n", + cp->cmd, inb(cp->pbase+Pstatus)); + error("ata drive timeout"); + } +} + +/* + * transfer a number of sectors. ataintr will perform all the iterative + * parts. + */ +static long +ataxfer(Drive *dp, Partition *pp, int cmd, long start, long len, char *buf) +{ + Controller *cp; + long lblk; + int cyl, sec, head; + int loop, stat; + + if(dp->online == 0) + error(Eio); + + /* + * cut transfer size down to disk buffer size + */ + start = start / dp->bytes; + if(len > Maxxfer) + len = Maxxfer; + len = (len + dp->bytes - 1) / dp->bytes; + if(len == 0) + return 0; + + /* + * calculate physical address + */ + lblk = start + pp->start; + if(lblk >= pp->end) + return 0; + if(lblk+len > pp->end) + len = pp->end - lblk; + if(dp->lba){ + sec = lblk & 0xff; + cyl = (lblk>>8) & 0xffff; + head = (lblk>>24) & 0xf; + } else { + cyl = lblk/(dp->sectors*dp->heads); + sec = (lblk % dp->sectors) + 1; + head = ((lblk/dp->sectors) % dp->heads); + } + + DPRINT("<%s %ld>", (cmd == Cwrite) ? "W" : "R", lblk); + cp = dp->cp; + qlock(cp); + if(waserror()){ + cp->buf = 0; + qunlock(cp); + nexterror(); + } + + /* + * Make sure hardclock() doesn't + * interfere. + */ + dp->usetime = m->ticks; + cmdreadywait(dp); + + ilock(&cp->reglock); + cp->sofar = 0; + cp->buf = buf; + cp->nsecs = len; + cp->cmd = cmd; + cp->dp = dp; + cp->status = 0; + + outb(cp->pbase+Pcount, cp->nsecs); + outb(cp->pbase+Psector, sec); + outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | (dp->lba<<6) | head); + outb(cp->pbase+Pcyllsb, cyl); + outb(cp->pbase+Pcylmsb, cyl>>8); + outb(cp->pbase+Pcmd, cmd); + + if(cmd == Cwrite){ + loop = 0; + microdelay(1); + while((stat = inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0) + if(++loop > 10000) + panic("ataxfer"); + outss(cp->pbase+Pdata, cp->buf, dp->bytes/2); + } else + stat = 0; + iunlock(&cp->reglock); + + if(stat & Serr) + error(Eio); + + /* + * wait for command to complete. if we get a note, + * remember it but keep waiting to let the disk finish + * the current command. + */ + loop = 0; + while(waserror()){ + DPRINT("interrupted ataxfer\n"); + if(loop++ > 10){ + print("ata disk error\n"); + nexterror(); + } + } + atasleep(cp, 3000); + dp->state = Sspinning; + dp->usetime = m->ticks; + poperror(); + if(loop) + nexterror(); + + if(cp->status & Serr){ + DPRINT("hd%ld err: lblk %ld status %ux, err %ux\n", + dp-ata, lblk, cp->status, cp->error); + DPRINT("\tcyl %d, sec %d, head %d\n", cyl, sec, head); + DPRINT("\tnsecs %d, sofar %d\n", cp->nsecs, cp->sofar); + atarepl(dp, lblk+cp->sofar); + error(Eio); + } + cp->buf = 0; + len = cp->sofar*dp->bytes; + qunlock(cp); + poperror(); + + return len; +} + +/* + * set read ahead mode + */ +static void +atasetbuf(Drive *dp, int on) +{ + Controller *cp = dp->cp; + + qlock(cp); + if(waserror()){ + qunlock(cp); + nexterror(); + } + + cmdreadywait(dp); + + ilock(&cp->reglock); + cp->cmd = Csetbuf; + outb(cp->pbase+Pprecomp, on ? 0xAA : 0x55); /* read look ahead */ + outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4)); + outb(cp->pbase+Pcmd, Csetbuf); + iunlock(&cp->reglock); + + atasleep(cp, 5000); + +/* if(cp->status & Serr) + DPRINT("hd%d setbuf err: status %lux, err %lux\n", + dp-ata, cp->status, cp->error);/**/ + + poperror(); + qunlock(cp); +} + +/* + * ident sector from drive. this is from ANSI X3.221-1994 + */ +struct Ident +{ + ushort config; /* general configuration info */ + ushort cyls; /* # of cylinders (default) */ + ushort reserved0; + ushort heads; /* # of heads (default) */ + ushort b2t; /* unformatted bytes/track */ + ushort b2s; /* unformated bytes/sector */ + ushort s2t; /* sectors/track (default) */ + ushort reserved1[3]; +/* 10 */ + ushort serial[10]; /* serial number */ + ushort type; /* buffer type */ + ushort bsize; /* buffer size/512 */ + ushort ecc; /* ecc bytes returned by read long */ + ushort firm[4]; /* firmware revision */ + ushort model[20]; /* model number */ +/* 47 */ + ushort s2i; /* number of sectors/interrupt */ + ushort dwtf; /* double word transfer flag */ + ushort capabilities; + ushort reserved2; + ushort piomode; + ushort dmamode; + ushort cvalid; /* (cvald&1) if next 4 words are valid */ + ushort ccyls; /* current # cylinders */ + ushort cheads; /* current # heads */ + ushort cs2t; /* current sectors/track */ + ushort ccap[2]; /* current capacity in sectors */ + ushort cs2i; /* current number of sectors/interrupt */ +/* 60 */ + ushort lbasecs[2]; /* # LBA user addressable sectors */ + ushort dmasingle; + ushort dmadouble; +/* 64 */ + ushort reserved3[64]; + ushort vendor[32]; /* vendor specific */ + ushort reserved4[96]; +}; + +/* + * get parameters from the drive + */ +static void +ataident(Drive *dp) +{ + Controller *cp; + char *buf; + Ident *ip; + char id[21]; + + cp = dp->cp; + buf = smalloc(Maxxfer); + qlock(cp); + if(waserror()){ + cp->buf = 0; + qunlock(cp); + free(buf); + nexterror(); + } + + cmdreadywait(dp); + + ilock(&cp->reglock); + cp->nsecs = 1; + cp->sofar = 0; + cp->cmd = Cident; + cp->dp = dp; + cp->buf = buf; + outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4)); + outb(cp->pbase+Pcmd, Cident); + iunlock(&cp->reglock); + + atasleep(cp, 5000); + if(cp->status & Serr){ + DPRINT("bad disk ident status\n"); + error(Eio); + } + ip = (Ident*)buf; + + /* + * this function appears to respond with an extra interrupt after + * the ident information is read, except on the safari. The following + * delay gives this extra interrupt a chance to happen while we are quiet. + * Otherwise, the interrupt may come during a subsequent read or write, + * causing a panic and much confusion. + */ + if (cp->cmd == Cident2) + tsleep(&cp->r, return0, 0, 10); + + memmove(id, ip->model, sizeof(id)-1); + id[sizeof(id)-1] = 0; + + if(ip->capabilities & (1<<9)){ + dp->lba = 1; + dp->sectors = (ip->lbasecs[0]) | (ip->lbasecs[1]<<16); + dp->cap = dp->bytes * dp->sectors; +/*print("\nata%d model %s with %d lba sectors\n", dp->drive, id, dp->sectors);/**/ + } else { + dp->lba = 0; + + /* use default (unformatted) settings */ + dp->cyl = ip->cyls; + dp->heads = ip->heads; + dp->sectors = ip->s2t; +/*print("\nata%d model %s with default %d cyl %d head %d sec\n", dp->drive, + id, dp->cyl, dp->heads, dp->sectors);/**/ + + if(ip->cvalid&(1<<0)){ + /* use current settings */ + dp->cyl = ip->ccyls; + dp->heads = ip->cheads; + dp->sectors = ip->cs2t; +/*print("\tchanged to %d cyl %d head %d sec\n", dp->cyl, dp->heads, dp->sectors);/**/ + } + dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors; + } + cp->lastcmd = cp->cmd; + cp->cmd = 0; + cp->buf = 0; + free(buf); + poperror(); + qunlock(cp); +} + +/* + * probe the given sector to see if it exists + */ +static int +ataprobe(Drive *dp, int cyl, int sec, int head) +{ + Controller *cp; + char *buf; + int rv; + + cp = dp->cp; + buf = smalloc(Maxxfer); + qlock(cp); + if(waserror()){ + free(buf); + qunlock(cp); + nexterror(); + } + + cmdreadywait(dp); + + ilock(&cp->reglock); + cp->cmd = Cread; + cp->dp = dp; + cp->status = 0; + cp->nsecs = 1; + cp->sofar = 0; + + outb(cp->pbase+Pcount, 1); + outb(cp->pbase+Psector, sec+1); + outb(cp->pbase+Pdh, DHmagic | head | (dp->lba<<6) | (dp->drive<<4)); + outb(cp->pbase+Pcyllsb, cyl); + outb(cp->pbase+Pcylmsb, cyl>>8); + outb(cp->pbase+Pcmd, Cread); + iunlock(&cp->reglock); + + atasleep(cp, 5000); + + if(cp->status & Serr) + rv = -1; + else + rv = 0; + + cp->buf = 0; + free(buf); + poperror(); + qunlock(cp); + return rv; +} + +/* + * figure out the drive parameters + */ +static void +ataparams(Drive *dp) +{ + int i, hi, lo; + + /* + * first try the easy way, ask the drive and make sure it + * isn't lying. + */ + dp->bytes = 512; + ataident(dp); + if(dp->lba){ + i = dp->sectors - 1; + if(ataprobe(dp, (i>>8)&0xffff, (i&0xff)-1, (i>>24)&0xf) == 0) + return; + } else { + if(ataprobe(dp, dp->cyl-1, dp->sectors-1, dp->heads-1) == 0) + return; + } + + /* + * the drive lied, determine parameters by seeing which ones + * work to read sectors. + */ + dp->lba = 0; + for(i = 0; i < 32; i++) + if(ataprobe(dp, 0, 0, i) < 0) + break; + dp->heads = i; + for(i = 0; i < 128; i++) + if(ataprobe(dp, 0, i, 0) < 0) + break; + dp->sectors = i; + for(i = 512; ; i += 512) + if(ataprobe(dp, i, dp->sectors-1, dp->heads-1) < 0) + break; + lo = i - 512; + hi = i; + for(; hi-lo > 1;){ + i = lo + (hi - lo)/2; + if(ataprobe(dp, i, dp->sectors-1, dp->heads-1) < 0) + hi = i; + else + lo = i; + } + dp->cyl = lo + 1; + dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors; +} + +/* + * Read block replacement table. + * The table is just ascii block numbers. + */ +static void +atareplinit(Drive *dp) +{ + char *line[Nrepl+1]; + char *field[1]; + ulong n; + int i; + char *buf; + + /* + * check the partition is big enough + */ + if(dp->repl.p->end - dp->repl.p->start < Nrepl+1){ + dp->repl.p = 0; + return; + } + + buf = smalloc(Maxxfer); + if(waserror()){ + free(buf); + nexterror(); + } + + /* + * read replacement table from disk, null terminate + */ + ataxfer(dp, dp->repl.p, Cread, 0, dp->bytes, buf); + buf[dp->bytes-1] = 0; + + /* + * parse replacement table. + */ + n = getfields(buf, line, Nrepl+1, 1, "\n"); + if(strncmp(line[0], REPLMAGIC, sizeof(REPLMAGIC)-1)){ + dp->repl.p = 0; + } else { + for(dp->repl.nrepl = 0, i = 1; i < n; i++, dp->repl.nrepl++){ + if(getfields(line[i], field, 1, 1, " ") != 1) + break; + dp->repl.blk[dp->repl.nrepl] = strtoul(field[0], 0, 0); + if(dp->repl.blk[dp->repl.nrepl] <= 0) + break; + } + } + free(buf); + poperror(); +} + +/* + * read partition table. The partition table is just ascii strings. + */ +static void +atapart(Drive *dp) +{ + Partition *pp; + char *line[Npart+1]; + char *field[3]; + ulong n; + int i; + char *buf; + + sprint(dp->vol, "hd%ld", dp - ata); + + /* + * we always have a partition for the whole disk + * and one for the partition table + */ + pp = &dp->p[0]; + strcpy(pp->name, "disk"); + pp->start = 0; + pp->end = dp->cap / dp->bytes; + pp++; + strcpy(pp->name, "partition"); + pp->start = dp->p[0].end - 1; + pp->end = dp->p[0].end; + pp++; + dp->npart = 2; + + /* + * initialise the bad-block replacement info + */ + dp->repl.p = 0; + + buf = smalloc(Maxxfer); + if(waserror()){ + free(buf); + nexterror(); + } + + /* + * read last sector from disk, null terminate. This used + * to be the sector we used for the partition tables. + * However, this sector is special on some PC's so we've + * started to use the second last sector as the partition + * table instead. To avoid reconfiguring all our old systems + * we first look to see if there is a valid partition + * table in the last sector. If so, we use it. Otherwise + * we switch to the second last. + */ + ataxfer(dp, dp->p+1, Cread, 0, dp->bytes, buf); + buf[dp->bytes-1] = 0; + n = getfields(buf, line, Npart+1, 1, "\n"); + if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){ + dp->p[0].end--; + dp->p[1].start--; + dp->p[1].end--; + ataxfer(dp, dp->p+1, Cread, 0, dp->bytes, buf); + buf[dp->bytes-1] = 0; + n = getfields(buf, line, Npart+1, 1, "\n"); + } + + /* + * parse partition table. + */ + if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){ + for(i = 1; i < n; i++){ + switch(getfields(line[i], field, 3, 1, " ")) { + case 2: + if(strcmp(field[0], "unit") == 0) + strncpy(dp->vol, field[1], KNAMELEN); + break; + case 3: + strncpy(pp->name, field[0], KNAMELEN); + if(strncmp(pp->name, "repl", KNAMELEN) == 0) + dp->repl.p = pp; + pp->start = strtoul(field[1], 0, 0); + pp->end = strtoul(field[2], 0, 0); + if(pp->start > pp->end || pp->end > dp->p[0].end) + break; + dp->npart++; + pp++; + } + } + } + free(buf); + poperror(); + + if(dp->repl.p) + atareplinit(dp); +} + +enum +{ + Maxloop= 10000, +}; + +/* + * we get an interrupt for every sector transferred + */ +static void +ataintr(Ureg*, void *arg) +{ + Controller *cp; + Drive *dp; + long loop; + char *addr; + + cp = arg; + dp = cp->dp; + + ilock(&cp->reglock); + + loop = 0; + while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy){ + if(++loop > Maxloop) { + DPRINT("cmd=%ux status=%ux\n", + cp->cmd, inb(cp->pbase+Pstatus)); + panic("ataintr: wait busy"); + } + } + + switch(cp->cmd){ + case Cwrite: + if(cp->status & Serr){ + cp->lastcmd = cp->cmd; + cp->cmd = 0; + cp->error = inb(cp->pbase+Perror); + wakeup(&cp->r); + break; + } + cp->sofar++; + if(cp->sofar < cp->nsecs){ + loop = 0; + while(((cp->status = inb(cp->pbase+Pstatus)) & Sdrq) == 0) + if(++loop > Maxloop) { + DPRINT("cmd=%ux status=%ux\n", + cp->cmd, inb(cp->pbase+Pstatus)); + panic("ataintr: write"); + } + addr = cp->buf; + if(addr){ + addr += cp->sofar*dp->bytes; + outss(cp->pbase+Pdata, addr, dp->bytes/2); + } + } else{ + cp->lastcmd = cp->cmd; + cp->cmd = 0; + wakeup(&cp->r); + } + break; + case Cread: + case Cident: + loop = 0; + while((cp->status & (Serr|Sdrq)) == 0){ + if(++loop > Maxloop) { + DPRINT("cmd=%ux status=%ux\n", + cp->cmd, inb(cp->pbase+Pstatus)); + panic("ataintr: read/ident"); + } + cp->status = inb(cp->pbase+Pstatus); + } + if(cp->status & Serr){ + cp->lastcmd = cp->cmd; + cp->cmd = 0; + cp->error = inb(cp->pbase+Perror); + wakeup(&cp->r); + break; + } + addr = cp->buf; + if(addr){ + addr += cp->sofar*dp->bytes; + inss(cp->pbase+Pdata, addr, dp->bytes/2); + } + cp->sofar++; + if(cp->sofar > cp->nsecs) + print("ataintr %d %d\n", cp->sofar, cp->nsecs); + if(cp->sofar >= cp->nsecs){ + cp->lastcmd = cp->cmd; + if (cp->cmd == Cread) + cp->cmd = 0; + else + cp->cmd = Cident2; + wakeup(&cp->r); + } + break; + case Cinitparam: + case Csetbuf: + case Cidle: + case Cstandby: + case Cpowerdown: + cp->lastcmd = cp->cmd; + cp->cmd = 0; + wakeup(&cp->r); + break; + case Cident2: + cp->lastcmd = cp->cmd; + cp->cmd = 0; + break; + default: + print("weird disk interrupt, cmd=%.2ux, lastcmd= %.2ux status=%.2ux\n", + cp->cmd, cp->lastcmd, cp->status); + break; + } + + iunlock(&cp->reglock); +} + +void +hardclock(void) +{ + int drive; + Drive *dp; + Controller *cp; + int diff; + + if(spindowntime <= 0) + return; + + for(drive = 0; drive < nhard; drive++){ + dp = &ata[drive]; + cp = dp->cp; + + diff = TK2SEC(m->ticks - dp->usetime); + if((dp->state == Sspinning) && (diff >= spindowntime)){ + ilock(&cp->reglock); + cp->cmd = Cstandby; + outb(cp->pbase+Pcount, 0); + outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | 0); + outb(cp->pbase+Pcmd, cp->cmd); + iunlock(&cp->reglock); + dp->state = Sstandby; + } + } +} + +Dev atadevtab = { + 'H', + "ata", + + devreset, + atainit, + devshutdown, + ataattach, + atawalk, + atastat, + ataopen, + devcreate, + ataclose, + ataread, + devbread, + atawrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/os/cerf1110/devcerf.c b/os/cerf1110/devcerf.c new file mode 100644 index 00000000..3c0fc999 --- /dev/null +++ b/os/cerf1110/devcerf.c @@ -0,0 +1,128 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "io.h" + + +enum{ + Qdir, + Qled, +}; + +static +Dirtab cerftab[]={ + ".", {Qdir, 0, QTDIR}, 0, 0555, + "cerfled", {Qled, 0}, 0, 0660, +}; + +static void +cerfinit(void) /* default in dev.c */ +{ + int s; + + s = splhi(); + GPIOREG->gpdr |= 0xF; + GPIOREG->gpsr = 1<<0; /* we're here */ + splx(s); +} + +static Chan* +cerfattach(char* spec) +{ + return devattach('T', spec); +} + +static Walkqid* +cerfwalk(Chan *c, Chan *nc, char **name, int nname) +{ + return devwalk(c, nc, name, nname, cerftab, nelem(cerftab), devgen); +} + +static int +cerfstat(Chan* c, uchar *db, int n) +{ + return devstat(c, db, n, cerftab, nelem(cerftab), devgen); +} + +static Chan* +cerfopen(Chan* c, int omode) +{ + return devopen(c, omode, cerftab, nelem(cerftab), devgen); +} + +static void +cerfclose(Chan* c) +{ + USED(c); +} + +static long +cerfread(Chan* c, void* a, long n, vlong offset) +{ + char buf[16]; + + switch((ulong)c->qid.path){ + case Qdir: + return devdirread(c, a, n, cerftab, nelem(cerftab), devgen); + case Qled: + snprint(buf, sizeof(buf), "%2.2lux", GPIOREG->gplr&0xF); + return readstr(offset, a, n, buf); + default: + n=0; + break; + } + return n; +} + +static long +cerfwrite(Chan* c, void* a, long n, vlong) +{ + char buf[16]; + ulong v; + + switch((ulong)c->qid.path){ + case Qled: + if(n >= sizeof(buf)) + n = sizeof(buf)-1; + memmove(buf, a, n); + buf[n] = 0; + v = GPIOREG->gplr & 0xF; + if(buf[0] == '+') + v |= strtoul(buf+1, nil, 0); + else if(buf[0] == '-') + v &= ~strtoul(buf+1, nil, 0); + else + v = strtoul(buf, nil, 0); + GPIOREG->gpsr = v & 0xF; + GPIOREG->gpcr = ~v & 0xF; + break; + default: + error(Ebadusefd); + } + return n; +} + +Dev cerfdevtab = { + 'T', + "cerf", + + devreset, + cerfinit, + devshutdown, + cerfattach, + cerfwalk, + cerfstat, + cerfopen, + devcreate, + cerfclose, + cerfread, + devbread, + cerfwrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/os/cerf1110/ether8900.c b/os/cerf1110/ether8900.c new file mode 100644 index 00000000..fc9ea12e --- /dev/null +++ b/os/cerf1110/ether8900.c @@ -0,0 +1,702 @@ +/* + * Crystal CS8900 ethernet controller + * + * Todo: + * - promiscuous + * + * Copyright © 1998 Vita Nuova Limited. All rights reserved. + * Revisions Copyright © 2000,2003 Vita Nuova Holdings Limited. All rights reserved. + */ + +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/netif.h" + +#include "etherif.h" + +typedef struct Ctlr Ctlr; + +/* + * The CS8900 can be addressed from either ISA I/O space + * or ISA memory space at the following virtual addresses, + * depending on the hardware's wiring. MEMORY controls + * use of memory space. + * The cs8900 address pins are shifted by 1 relative to the CPU. + */ +enum {//18000000 + IsaIOBase = 0x08000000, + IsaMemBase = 0xe0000000, + + IOBase = 0x300, + MemBase = 0xc0000, + + MEMORY = 0, /* set non-zero if memory mode to be used */ + DORESET = 1, /* send soft-reset during initialisation */ + DEBUG = 0, +}; + +#define IOSHIFT 0 /* was 2 */ +#define IOREG(r) (IsaIOBase+((IOBase+(r))<<IOSHIFT)) + +/* I/O accesses */ +#define out16(port, val) (*((ushort *)IOREG(port)) = (val)) +#define in16(port) *((ushort *)IOREG(port)) +#define in8(port) *((uchar *)IOREG(port)) +#define regIOw(reg, val) do {out16(PpPtr, (reg)|0x3000); out16(PpData, val);} while(0) +#define regIOr(reg) (out16(PpPtr, (reg)|0x3000), in16(PpData)) +#define regIOr1(reg) (out16(PpPtr, (reg)|0x3000), in16(PpData1)) + +/* Memory accesses */ + +#define REGW(reg, val) *((ushort *)IsaMemBase + MemBase + (reg)) = (val) +#define REGR(reg) *((ushort *)IsaMemBase + MemBase + (reg)) + +enum { /* I/O Mode Register Offsets */ + RxTxData = 0x00, /* receive/transmit data - port 0 */ + RxTxData1 = 0x02, /* r/t data port 1 */ + TxCmdIO = 0x04, /* transmit command */ + TxLenIO = 0x06, /* transmit length */ + IsqIO = 0x08, /* Interrupt status queue */ + PpPtr = 0x0a, /* packet page pointer */ + PpData = 0x0c, /* packet page data */ + PpData1 = 0x0e, /* packet page data - port 1*/ +}; + +enum { /* Memory Mode Register Offsets */ + /* Bus Interface Registers */ + Ern = 0x0000, /* EISA registration numberion */ + Pic = 0x0002, /* Product identification code */ + Iob = 0x0020, /* I/O base address */ + Intr = 0x0022, /* interrupt number */ + Mba = 0x002c, /* memory base address */ + + Ecr = 0x0040, /* EEPROM command register */ + Edw = 0x0042, /* EEPROM data word */ + Rbc = 0x0050, /* receive frame byte counter */ + + /* Status and Control Registers */ + RxCfg = 0x0102, + RxCtl = 0x0104, + TxCfg = 0x0106, + BufCfg = 0x010a, + LineCtl = 0x0112, + SelfCtl = 0x0114, + BusCtl = 0x0116, + TestCtl = 0x0118, + Isq = 0x0120, + RxEvent = 0x0124, + TxEvent = 0x0128, + BufEvent = 0x012c, + RxMISS = 0x0130, + TxCol = 0x0132, + LineSt = 0x0134, + SelfSt = 0x0136, + BusSt = 0x0138, + Tdr = 0x013c, + + /* Initiate Transmit Registers */ + TxCmd = 0x0144, /* transmit command */ + TxLen = 0x0146, /* transmit length */ + + /* Address Filter Registers */ + IndAddr = 0x0158, /* individual address registers */ + + /* Frame Location */ + RxStatus = 0x0400, /* receive status */ + RxLen = 0x0402, /* receive length */ + RxFrame = 0x0404, /* receive frame location */ + TxFrame = 0x0a00, /* transmit frame location */ +}; + +enum { /* Ecr */ + Addr = 0x00ff, /* EEPROM word address (field) */ + Opcode = 0x0300, /* command opcode (field) */ + EEread = 0x0200, + EEwrite = 0x0100, +}; + +enum { /* Isq */ + Regnum = 0x003f, /* register number held by Isq (field) */ + IsqRxEvent = 0x04, + IsqTxEvent = 0x08, + IsqBufEvent = 0x0c, + IsqRxMiss = 0x10, + IsqTxCol = 0x12, + RegContent = 0xffc0, /* register data contents (field) */ +}; + +enum { /* RxCfg */ + Skip_1 = 0x0040, + StreamE = 0x0080, + RxOKiE = 0x0100, + RxDMAonly = 0x0200, + AutoRxDMAE = 0x0400, + BufferCRC = 0x0800, + CRCerroriE = 0x1000, + RuntiE = 0x2000, + ExtradataiE = 0x4000, +}; + +enum { /* RxEvent */ + IAHash = 0x0040, + Dribblebits = 0x0080, + RxOK = 0x0100, + Hashed = 0x0200, + IndividualAdr = 0x0400, + Broadcast = 0x0800, + CRCerror = 0x1000, + Runt = 0x2000, + Extradata = 0x4000, +}; + +enum { /* RxCtl */ + IAHashA = 0x0040, + PromiscuousA = 0x0080, + RxOKA = 0x0100, + MulticastA = 0x0200, + IndividualA = 0x0400, + BroadcastA = 0x0800, + CRCerrorA = 0x1000, + RuntA = 0x2000, + ExtradataA = 0x4000, +}; + +enum { /* TxCfg */ + LossofCRSiE = 0x0040, + SQEerroriE = 0x0080, + TxOKiE = 0x0100, + OutofWindowiE = 0x0200, + JabberiE = 0x0400, + AnycolliE = 0x0800, + Coll16iE = 0x8000, +}; + +enum { /* TxEvent */ + LossofCRS = 0x0040, + SQEerror = 0x0080, + TxOK = 0x0100, + OutofWindow = 0x0200, + Jabber = 0x0400, + NTxCols = 0x7800, /* number of Tx collisions (field) */ + coll16 = 0x8000, +}; + +enum { /* BufCfg */ + SWintX = 0x0040, + RxDMAiE = 0x0080, + Rdy4TxiE = 0x0100, + TxUnderruniE = 0x0200, + RxMissiE = 0x0400, + Rx128iE = 0x0800, + TxColOvfiE = 0x1000, + MissOvfloiE = 0x2000, + RxDestiE = 0x8000, +}; + +enum { /* BufEvent */ + SWint = 0x0040, + RxDMAFrame = 0x0080, + Rdy4Tx = 0x0100, + TxUnderrun = 0x0200, + RxMiss = 0x0400, + Rx128 = 0x0800, + RxDest = 0x8000, +}; + +enum { /* RxMiss */ + MissCount = 0xffc0, +}; + +enum { /* TxCol */ + ColCount = 0xffc0, +}; + +enum { /* LineCtl */ + SerRxOn = 0x0040, + SerTxOn = 0x0080, + Iface = 0x0300, /* (field) 01 - AUI, 00 - 10BASE-T, 10 - Auto select */ + ModBackoffE = 0x0800, + PolarityDis = 0x1000, + DefDis = 0x2000, + LoRxSquelch = 0x4000, +}; + +enum { /* LineSt */ + LinkOK = 0x0080, + AUI = 0x0100, + TenBT = 0x0200, + PolarityOK = 0x1000, + CRS = 0x4000, +}; + +enum { /* SelfCtl */ + RESET = 0x0040, + SWSuspend = 0x0100, + HWSleepE = 0x0200, + HWStandbyE = 0x0400, +}; + +enum { /* SelfSt */ + Active3V = 0x0040, + INITD = 0x0080, + SIBUSY = 0x0100, + EepromPresent = 0x0200, + EepromOK = 0x0400, + ElPresent = 0x0800, + EeSize = 0x1000, +}; + +enum { /* BusCtl */ + ResetRxDMA = 0x0040, + UseSA = 0x0200, + MemoryE = 0x0400, + DMABurst = 0x0800, + EnableIRQ = 0x8000, +}; + +enum { /* BusST */ + TxBidErr = 0x0080, + Rdy4TxNOW = 0x0100, +}; + +enum { /* TestCtl */ + FDX = 0x4000, /* full duplex */ +}; + +enum { /* TxCmd */ + TxStart = 0x00c0, /* bytes before transmit starts (field) */ + TxSt5 = 0x0000, /* start after 5 bytes */ + TxSt381 = 0x0040, /* start after 381 bytes */ + TxSt1021 = 0x0080, /* start after 1021 bytes */ + TxStAll = 0x00c0, /* start after the entire frame is in the cs8900 */ + Force = 0x0100, + Onecoll = 0x0200, + InhibitCRC = 0x1000, + TxPadDis = 0x2000, +}; + +enum { /* EEPROM format */ + Edataoff = 0x1C, /* start of data (ether address) */ + Edatalen = 0x14, /* data count in 16-bit words */ +}; + +struct Ctlr { + Lock; + Block* waiting; /* waiting for space in FIFO */ + int model; + int rev; + + ulong collisions; +}; + +static void +regw(int reg, int val) +{ + if(DEBUG) + print("r%4.4ux <- %4.4ux\n", reg, val); + if(MEMORY){ + REGW(reg, val); + }else{ + out16(PpPtr, reg); + out16(PpData, val); + } +} + +static int +regr(int reg) +{ + int v; + + if(MEMORY) + return REGR(reg); + out16(PpPtr, reg); + v = in16(PpData); + if(DEBUG) + print("r%4.4ux = %4.4ux\n", reg, v); + return v; +} + +/* + * copy frames in and out, accounting for shorts aligned as longs in IO memory + */ + +static void +copypktin(void *ad, int len) +{ + ushort *s, *d; + int ns; + + if(!MEMORY){ + d = ad; + /* + * contrary to data sheet DS271PP3 pages 77-78, + * the data is not preceded by status & length + * perhaps because it has been read directly. + */ + for(ns = len>>1; --ns >= 0;) + *d++ = in16(RxTxData); + if(len & 1) + *(uchar*)d = in16(RxTxData); + return; + } + d = ad; + s = (ushort*)IsaMemBase + MemBase + RxFrame; + for(ns = len>>1; --ns >= 0;){ + *d++ = *s; + s += 2; + } + if(len & 1) + *(uchar*)d = *s; +} + +static void +copypktout(void *as, int len) +{ + ushort *s, *d; + int ns; + + if(!MEMORY){ + s = as; + ns = (len+1)>>1; + while(--ns >= 0) + out16(RxTxData, *s++); + return; + } + s = as; + d = (ushort*)IsaMemBase + MemBase + TxFrame; + ns = (len+1)>>1; + while(--ns >= 0){ + *d = *s++; + d += 2; + } +} + +static long +ifstat(Ether* ether, void* a, long n, ulong offset) +{ + Ctlr *ctlr; + char *p; + int len; + + if(n == 0) + return 0; + + ctlr = ether->ctlr; + p = malloc(READSTR); + len = snprint(p, READSTR, "Overflow: %ud\n", ether->overflows); + len += snprint(p+len, READSTR-len, "CRC Error: %ud\n", ether->crcs); + snprint(p+len, READSTR-len, "Collision Seen: %lud\n", ctlr->collisions); + + n = readstr(offset, a, n, p); + free(p); + + return n; +} + +static void +promiscuous(void* arg, int on) +{ + USED(arg, on); +} + +static void +attach(Ether *ether) +{ + int reg; + + USED(ether); + /* enable transmit and receive */ + reg = regr(BusCtl); + regw(BusCtl, reg|EnableIRQ); + reg = regr(LineCtl); + regw(LineCtl, reg|SerRxOn|SerTxOn); + if(DEBUG){ + iprint("bus=%4.4ux line=%4.4ux\n", regr(BusCtl), regr(LineCtl)); + iprint("rc=%4.4ux tc=%4.4ux bc=%4.4ux\n", regr(RxCfg), regr(TxCfg), regr(BufCfg)); + } +} + +static void +txstart(Ether *ether, int dowait) +{ + int len, status; + Ctlr *ctlr; + Block *b; + + ctlr = ether->ctlr; + for(;;){ + if((b = ctlr->waiting) == nil){ + if((b = qget(ether->oq)) == nil) + break; + }else{ + if(!dowait) + break; + ctlr->waiting = nil; + } + len = BLEN(b); + if(MEMORY){ + regw(TxCmd, TxSt381); + regw(TxLen, len); + }else{ + out16(TxCmdIO, TxStAll); + out16(TxLenIO, len); + } + status = regr(BusSt); + if((status & Rdy4TxNOW) == 0) { + ctlr->waiting = b; + break; + } + /* + * Copy the packet to the transmit buffer. + */ + copypktout(b->rp, len); + freeb(b); + } +} + +static void +transmit(Ether *ether) +{ + Ctlr *ctlr; + + ctlr = ether->ctlr; + ilock(ctlr); + txstart(ether, 0); + iunlock(ctlr); +} + +static void +interrupt(Ureg*, void *arg) +{ + Ether *ether; + Ctlr *ctlr; + int len, events, status; + Block *b; + + ether = arg; + ctlr = ether->ctlr; + ilock(ctlr); + while((events = (MEMORY?regr(Isq):in16(IsqIO))) != 0) { + status = events&RegContent; + if(DEBUG) + iprint("status %4.4ux event %4.4ux\n", status, events); + switch(events&Regnum) { + + case IsqBufEvent: + if(status&Rdy4Tx) { + if((b = ctlr->waiting) != nil){ + ctlr->waiting = nil; + copypktout(b->rp, BLEN(b)); + freeb(b); + /* wait for IsqTxEvent to send remaining packets in txstart */ + }else + txstart(ether, 0); + } + break; + + case IsqRxEvent: + if(status&RxOK) { + len = regr(RxLen); + if(DEBUG) + iprint("rxlen=%d\n", len); + if((b = iallocb(len)) != 0) { + copypktin(b->wp, len); + b->wp += len; + etheriq(ether, b, 1); + } + } + break; + + case IsqTxEvent: + if(status&TxOK) + txstart(ether, 1); + break; + + case IsqRxMiss: + ether->overflows++; + break; + + case IsqTxCol: + ctlr->collisions++; + break; + } + } + iunlock(ctlr); +} + +static int +eepromwait(void) +{ + int i; + + for(i=0; i<100000; i++) + if((regIOr(SelfSt) & SIBUSY) == 0) + return 0; + return -1; +} + +static int +eepromrd(void *buf, int off, int n) +{ + int i; + ushort *p; + + p = buf; + n /= 2; + for(i=0; i<n; i++){ + if(eepromwait() < 0) + return -1; + regIOw(Ecr, EEread | (off+i)); + if(eepromwait() < 0) + return -1; + p[i] = regIOr(Edw); + } + return 0; +} + +static int +reset(Ether* ether) +{ + int i, reg, easet; + uchar ea[Eaddrlen]; + ushort buf[Edatalen]; + Ctlr *ctlr; + + if(!MEMORY) + mmuphysmap(IsaIOBase, 64*1024); + + delay(120); /* allow time for chip to reset */ + + if(0){ + *(ushort*)IsaIOBase = 0xDEAD; /* force rubbish on bus */ + for(i=0; i<100; i++){ + if(in16(PpPtr) == 0x3000) + break; + delay(1); + } + if(i>=100){ + iprint("failed init: reg(0xA): %4.4ux, should be 0x3000\n", in16(PpPtr)); + return -1; + } + } +iprint("8900: %4.4ux (selfst) %4.4ux (linest)\n", regIOr(SelfSt), regIOr(LineSt)); +iprint("8900: %4.4ux %4.4ux\n", regIOr(Ern), regIOr(Pic)); + + /* + * Identify the chip by reading the Pic register. + * The EISA registration number is in the low word + * and the product identification code in the high code. + * The ERN for Crystal Semiconductor is 0x630e. + * Bits 0-7 and 13-15 of the Pic should be zero for a CS8900. + */ + if(regIOr(Ern) != 0x630e || (regIOr(Pic) & 0xe0ff) != 0) + return -1; + + if(ether->ctlr == nil) + ether->ctlr = malloc(sizeof(Ctlr)); + ctlr = ether->ctlr; + + reg = regIOr(Pic); + ctlr->model = reg>>14; + ctlr->rev = (reg >> 8) & 0x1F; + + ether->mbps = 10; + + memset(ea, 0, Eaddrlen); + easet = memcmp(ea, ether->ea, Eaddrlen); + memset(buf, 0, sizeof(buf)); + if(regIOr(SelfSt) & EepromPresent) { /* worth a look */ + if(eepromrd(buf, Edataoff, sizeof(buf)) >= 0){ + for(i=0; i<3; i++){ + ether->ea[2*i] = buf[i]; + ether->ea[2*i+1] = buf[i] >> 8; + } + easet = 1; + }else + iprint("cs8900: can't read EEPROM\n"); + } + if(!easet){ + iprint("cs8900: ethernet address not configured\n"); + return -1; + } + memmove(ea, ether->ea, Eaddrlen); + + if(DORESET){ + /* + * Reset the chip and ensure 16-bit mode operation + */ + regIOw(SelfCtl, RESET); + delay(10); + i=in8(PpPtr); USED(i); + i=in8(PpPtr+1); USED(i); + i=in8(PpPtr); USED(i); + i=in8(PpPtr+1); USED(i); + + /* + * Wait for initialisation and EEPROM reads to complete + */ + i=0; + for(;;) { + short st = regIOr(SelfSt); + if((st&SIBUSY) == 0 && st&INITD) + break; + if(i++ > 1000000) + panic("cs8900: initialisation failed"); + } + } + + if(MEMORY){ + /* + * Enable memory mode operation. + */ + regIOw(Mba, MemBase & 0xffff); + regIOw(Mba+2, MemBase >> 16); + regIOw(BusCtl, MemoryE|UseSA); + } + + /* + * Enable 10BASE-T half duplex, transmit in interrupt mode + */ + reg = regr(LineCtl); + regw(LineCtl, reg&~Iface); + reg = regr(TestCtl); + if(ether->fullduplex) + regw(TestCtl, reg|FDX); + else + regw(TestCtl, reg&~FDX); + regw(BufCfg, Rdy4TxiE|TxUnderruniE); + regw(TxCfg, TxOKiE|AnycolliE|LossofCRSiE|Coll16iE); + regw(RxCfg, RxOKiE|CRCerroriE|RuntiE|ExtradataiE); + regw(RxCtl, RxOKA|IndividualA|BroadcastA); + + for(i=0; i<Eaddrlen; i+=2) + regw(IndAddr+i, ea[i] | (ea[i+1] << 8)); + + /* IRQ tied to INTRQ0 */ + regw(Intr, 0); + + /* + * Linkage to the generic ethernet driver. + */ + ether->attach = attach; + ether->transmit = transmit; + ether->interrupt = interrupt; + ether->ifstat = ifstat; + + ether->arg = ether; + ether->promiscuous = promiscuous; + + ether->itype = BusGPIOrising; /* TO DO: this shouldn't be done here */ + + return 0; +} + +void +ether8900link(void) +{ + addethercard("CS8900", reset); +} diff --git a/os/cerf1110/fns.h b/os/cerf1110/fns.h new file mode 100644 index 00000000..2ad379e4 --- /dev/null +++ b/os/cerf1110/fns.h @@ -0,0 +1,179 @@ +#include "../port/portfns.h" + +ulong aifinit(uchar *aifarr); +void aamloop(int); +int archaudiopower(int); +void archaudiomute(int); +void archaudioamp(int); +int archaudiospeed(int, int); +void archcodecreset(void); +void archconfinit(void); +void archconsole(void); +int archflash12v(int); +int archhooksw(int); +long archkprofmicrosecondspertick(void); +void archkprofenable(int); +void archlcdenable(int); +void archpowerdown(void); +void archpowerup(void); +void archreboot(void); +void archreset(void); +vlong archrdtsc(void); +ulong archrdtsc32(void); +void archuartpower(int, int); +void blankscreen(int); +ulong call_apcs(ulong addr, int nargs, ...); +ulong call_apcs0(ulong addr); +ulong call_apcs1(ulong addr, ulong a1); +ulong call_apcs2(ulong addr, ulong a1, ulong a2); +ulong call_apcs3(ulong addr, ulong a1, ulong a2, ulong a3); +void cisread(int slotno, void (*f)(int, uchar *)); +void clockcheck(void); +void clockinit(void); +void clockpoll(void); +#define coherence() /* nothing to do for cache coherence for uniprocessor */ +void cursorhide(void); +void cursorunhide(void); +void dcflush(void*, ulong); +void dcflushall(void); +void dcinval(void); +int dmaidle(Dma*); +Dma* dmasetup(int device, int direction, int bigend, void(*)(void*,ulong), void*); +int dmastart(Dma*, void*, int); +int dmacontinue(Dma*, void*, int); +void dmastop(Dma*); +int dmaerror(Dma*); +void dmafree(Dma*); +void dmareset(void); +void dmawait(Dma*); +void dumplongs(char *, ulong *, int); +void dumpregs(Ureg* ureg); +void dumpstack(void); +int fpiarm(Ureg*); +void fpinit(void); +ulong getcallerpc(void*); +ulong getcpsr(void); +ulong getcpuid(void); +ulong getspsr(void); +void gotopc(ulong); + +void icflushall(void); +void _idlemode(void); +void (*idle)(void); +void idlehands(void); +int inb(ulong); +int ins(ulong); +ulong inl(ulong); +void outb(ulong, int); +void outs(ulong, int); +void outl(ulong, ulong); +void inss(ulong, void*, int); +void outss(ulong, void*, int); +void insb(ulong, void*, int); +void outsb(ulong, void*, int); +void intrdisable(int, void (*)(Ureg*, void*), void*, int, char*); +void intrenable(int, void (*)(Ureg*, void*), void*, int, char*); +void iofree(int); +#define iofree(x) +void ioinit(void); +int iounused(int, int); +int ioalloc(int, int, int, char*); +#define ioalloc(a,b,c,d) 0 +int iprint(char*, ...); +void installprof(void (*)(Ureg *, int)); +int isvalid_va(void*); +void kbdinit(void); +void L3init(void); +int L3read(int, void*, int); +int L3write(int, void*, int); +void lcd_setbacklight(int); +void lcd_sethz(int); +void lights(ulong); +void links(void); +ulong mcpgettfreq(void); +void mcpinit(void); +void mcpsettfreq(ulong tfreq); +void mcpspeaker(int, int); +void mcptelecomsetup(ulong hz, int adm, int xint, int rint); +ushort mcpadcread(int ts); +void mcptouchsetup(int ts); +void mcptouchintrenable(void); +void mcptouchintrdisable(void); +void mcpgpiowrite(ushort mask, ushort data); +void mcpgpiosetdir(ushort mask, ushort dir); +ushort mcpgpioread(void); +void* minicached(void*); +void minidcflush(void); +void mmuenable(ulong); +ulong mmugetctl(void); +ulong mmugetdac(void); +ulong mmugetfar(void); +ulong mmugetfsr(void); +void mmuinit(void); +void* mmuphysmap(ulong, ulong); +void mmuputctl(ulong); +void mmuputdac(ulong); +void mmuputfsr(ulong); +void mmuputttb(ulong); +void mmureset(void); +void mouseinit(void); +void nowriteSeg(void *, void *); +void* pa2va(ulong); +void pcmcisread(PCMslot*); +int pcmcistuple(int, int, int, void*, int); +PCMmap* pcmmap(int, ulong, int, int); +void pcmunmap(int, PCMmap*); +int pcmpin(int slot, int type); +void pcmpower(int slotno, int on); +int pcmpowered(int); +void pcmreset(int); +void pcmsetvcc(int, int); +void pcmsetvpp(int, int); +int pcmspecial(char *idstr, ISAConf *isa); +void pcmspecialclose(int slotno); +void pcmintrenable(int, void (*)(Ureg*, void*), void*); +void powerenable(void (*)(int)); +void powerdisable(void (*)(int)); +void powerdown(void); +void powerinit(void); +void powersuspend(void); +#define procsave(p) +#define procrestore(p) +long rtctime(void); +void screeninit(void); +void (*screenputs)(char*, int); +int segflush(void*, ulong); +void setpanic(void); +void setr13(int, void*); +int splfhi(void); +int splflo(void); +void _suspendcode(void); +void tlbinvalidate(void); +void tlbinvalidateaddr(void*); +void trapinit(void); +void trapstacks(void); +void trapspecial(int (*)(Ureg *, uint)); +int uartprint(char*, ...); +void uartspecial(int, int, char, Queue**, Queue**, int (*)(Queue*, int)); +ulong va2pa(void*); +void vectors(void); +void vtable(void); +#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1])) +int wasbusy(int); + +#define KADDR(p) ((void *) p) +#define PADDR(v) va2pa((void*)(v)) + +// #define timer_start() (*OSCR) +// #define timer_ticks(t) (*OSCR - (ulong)(t)) +ulong timer_start(void); +ulong timer_ticks(ulong); +int timer_devwait(ulong *adr, ulong mask, ulong val, int ost); +void timer_setwatchdog(int ost); +void timer_delay(int ost); +ulong ms2tmr(int ms); +int tmr2ms(ulong t); +void delay(int ms); +ulong us2tmr(int us); +int tmr2us(ulong t); +void microdelay(int us); diff --git a/os/cerf1110/io.h b/os/cerf1110/io.h new file mode 100644 index 00000000..4e8cbc39 --- /dev/null +++ b/os/cerf1110/io.h @@ -0,0 +1 @@ +#include "../sa1110/sa1110io.h" diff --git a/os/cerf1110/main.c b/os/cerf1110/main.c new file mode 100644 index 00000000..58bd792f --- /dev/null +++ b/os/cerf1110/main.c @@ -0,0 +1,255 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "io.h" +#include "version.h" + +Mach *m = (Mach*)MACHADDR; +Proc *up = 0; +Vectorpage *page0 = (Vectorpage*)KZERO; /* doubly-mapped to AIVECADDR */ +Conf conf; + +extern ulong kerndate; +extern int cflag; +extern int main_pool_pcnt; +extern int heap_pool_pcnt; +extern int image_pool_pcnt; +ulong cpuidlecount; + +static void +poolsizeinit(void) +{ + ulong nb; + + nb = conf.npage*BY2PG; + 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 +main(void) +{ + memset(edata, 0, end-edata); /* clear the BSS */ + memset(m, 0, sizeof(Mach)); /* clear the mach struct */ + conf.nmach = 1; + archreset(); + dmareset(); + quotefmtinstall(); + confinit(); + xinit(); + mmuinit(); + poolinit(); + poolsizeinit(); + trapinit(); + clockinit(); + printinit(); + screeninit(); + procinit(); + links(); + chandevreset(); + + eve = strdup("inferno"); + + archconsole(); + kbdinit(); + + print("%ld MHz id %8.8lux\n", (m->cpuhz+500000)/1000000, getcpuid()); + print("\nInferno %s\n", VERSION); + print("Vita Nuova\n"); + print("conf %s (%lud) jit %d\n\n",conffile, kerndate, cflag); + + userinit(); + schedinit(); +} + +void +reboot(void) +{ + exit(0); +} + +void +halt(void) +{ + spllo(); + print("cpu halted\n"); + for(;;){ + /* nothing to do */ + } +} + +void +confinit(void) +{ + ulong base; + + archconfinit(); + + base = PGROUND((ulong)end); + conf.base0 = base; + + conf.base1 = 0; + conf.npage1 = 0; + + conf.npage0 = (conf.topofmem - base)/BY2PG; + + conf.npage = conf.npage0 + conf.npage1; + conf.ialloc = (((conf.npage*(main_pool_pcnt))/100)/2)*BY2PG; + + conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5; + conf.nmach = 1; + +} + +void +init0(void) +{ + Osenv *o; + char buf[2*KNAMELEN]; + + up->nerrlab = 0; + + spllo(); + + if(waserror()) + panic("init0 %r"); + /* + * 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(); + + if(!waserror()){ + ksetenv("cputype", "arm", 0); + snprint(buf, sizeof(buf), "arm %s", conffile); + ksetenv("terminal", buf, 0); + poperror(); + } + + poperror(); + + disinit("/osinit.dis"); +} + +void +userinit(void) +{ + Proc *p; + Osenv *o; + + p = newproc(); + o = p->env; + + o->fgrp = newfgrp(nil); + o->pgrp = newpgrp(); + o->egrp = newegrp(); + kstrdup(&o->user, eve); + + strcpy(p->text, "interp"); + + p->fpstate = FPINIT; + + /* + * Kernel Stack + * + * N.B. The -12 for the stack pointer is important. + * 4 bytes for gotolabel's return PC + */ + p->sched.pc = (ulong)init0; + p->sched.sp = (ulong)p->kstack+KSTACK-8; + + ready(p); +} + +void +exit(int inpanic) +{ + up = 0; + + /* Shutdown running devices */ + chandevshutdown(); + + if(inpanic && 0){ + print("Hit the reset button\n"); + for(;;) + clockpoll(); + } + archreboot(); +} + +static void +linkproc(void) +{ + spllo(); + if (waserror()) + print("error() underflow: %r\n"); + else + (*up->kpfun)(up->arg); + pexit("end proc", 1); +} + +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 +idlehands(void) +{ + cpuidlecount++; + INTRREG->iccr = 1; /* only unmasked interrupts will stop idle mode */ + idle(); +} + +/* stubs */ +void +setfsr(ulong) +{ +} + +ulong +getfsr() +{ + return 0; +} + +void +setfcr(ulong) +{ +} + +ulong +getfcr() +{ + return 0; +} + +void +fpinit(void) +{ +} + +void +FPsave(void*) +{ +} + +void +FPrestore(void*) +{ +} diff --git a/os/cerf1110/mem.h b/os/cerf1110/mem.h new file mode 100644 index 00000000..19d55b07 --- /dev/null +++ b/os/cerf1110/mem.h @@ -0,0 +1,200 @@ +/* + * 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 BIT(n) (1<<n) +#define BITS(a,b) ((1<<(b+1))-(1<<a)) + +#define MAXMACH 1 /* max # cpus system can run */ + +/* + * Time + */ +#define HZ (100) /* clock frequency */ +#define MS2HZ (1000/HZ) /* millisec per clock tick */ +#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */ +#define MS2TK(t) ((t)/MS2HZ) /* milliseconds to ticks */ + +/* + * More accurate time + */ +#define CLOCKFREQ 3686400 +#define MS2TMR(t) ((ulong)(((uvlong)(t)*CLOCKFREQ)/1000)) +#define US2TMR(t) ((ulong)(((uvlong)(t)*CLOCKFREQ)/1000000)) + +/* + * Address spaces + * nearly everything maps 1-1 with physical addresses + * 0 to 1Mb is not mapped + * cache strategy varies as needed (see mmu.c) + */ + +#define KZERO 0xC0000000 +#define MACHADDR (KZERO+0x00001000) +#define KTTB (KZERO+0x00004000) +#define KTZERO (KZERO+0x00008010) +#define KSTACK 8192 /* Size of kernel stack */ +#define FLASHMEM 0x50000000 /* map flash at phys 0 to otherwise unused virtual space */ +#define FLUSHMEM 0xE0000000 /* internally decoded zero memory (for cache flushing) */ +#define DCFADDR FLUSHMEM /* cached and buffered for cache writeback */ +#define MCFADDR (FLUSHMEM+(1<<20)) /* cached and unbuffered for minicache writeback */ +#define UCDRAMZERO 0xC8000000 /* base of memory doubly-mapped as uncached */ +#define AIVECADDR 0xFFFF0000 /* alternative interrupt vector address (other is 0) */ + +/* + * Physical addresses + */ +#define PHYSFLASH0 0x00000000 /* flash (chip select 0) */ +#define PHYSCS1 0x08000000 /* static chip select 1 */ +#define PHYSCS2 0x10000000 /* static chip select 2 */ +#define PHYSCS3 0x18000000 /* static chip select 3 */ +#define PHYSPCMCIA0 0x20000000 /* PCMCIA socket 0 space */ +#define PHYSPCMCIA1 0x30000000 /* PCMCIA socket 1 space */ +#define PCMCIASIZE 0x10000000 /* they're both huge */ +#define PHYSCS4 0x40000000 /* static chip select 4 */ +#define PHYSCS5 0x48000000 /* static chip select 5 */ +#define PHYSSERIAL(n) (0x80000000+0x10000*(n)) /* serial devices */ +#define PHYSUSB 0x80000000 +#define PHYSGPCLK 0x80020060 +#define PHYSMCP 0x80060000 +#define PHYSSSP 0x80070060 +#define PHYSOSTMR 0x90000000 /* timers */ +#define PHYSRTC 0x90010000 /* real time clock */ +#define PHYSPOWER 0x90020000 /* power management registers */ +#define PHYSRESET 0x90030000 /* reset controller */ +#define PHYSGPIO 0x90040000 +#define PHYSINTR 0x90050000 /* interrupt controller */ +#define PHYSPPC 0x90060000 /* peripheral pin controller */ +#define PHYSMEMCFG 0xA0000000 /* memory configuration */ +#define PHYSDMA 0xB0000000 /* DMA controller */ +#define PHYSLCD 0xB0100000 /* LCD controller */ +#define PHYSMEM0 0xC0000000 +#define PHYSFLUSH0 0xE0000000 /* internally decoded, for cache flushing */ + +/* + * Memory Interface Control Registers + */ +#define MDCNFG (PHYSMEMCFG) /* memory controller configuration */ +#define MDCAS0 (PHYSMEMCFG+4) +#define MDCAS1 (PHYSMEMCFG+8) +#define MDCAS2 (PHYSMEMCFG+0xC) +#define MSC0 (PHYSMEMCFG+0x10) +#define MSC1 (PHYSMEMCFG+0x14) +#define MSC2 (PHYSMEMCFG+0x2C) /* SA1110, but not SA1100 */ + +#define MSCx(RRR, RDN, RDF, RBW, RT) ((((RRR)&0x7)<<13)|(((RDN)&0x1F)<<8)|(((RDF)&0x1F)<<3)|(((RBW)&1)<<2)|((RT)&3)) + +#define CACHELINELOG 5 +#define CACHELINESZ (1<<CACHELINELOG) + +/* + * PSR + */ +#define PsrMusr 0x10 /* mode */ +#define PsrMfiq 0x11 +#define PsrMirq 0x12 +#define PsrMsvc 0x13 +#define PsrMabt 0x17 +#define PsrMund 0x1B +#define PsrMsys 0x1F +#define PsrMask 0x1F + +#define PsrDfiq 0x00000040 /* disable FIQ interrupts */ +#define PsrDirq 0x00000080 /* disable IRQ interrupts */ + +#define PsrV 0x10000000 /* overflow */ +#define PsrC 0x20000000 /* carry/borrow/extend */ +#define PsrZ 0x40000000 /* zero */ +#define PsrN 0x80000000 /* negative/less than */ + +/* + * Internal MMU coprocessor registers + */ +#define CpCPUID 0 /* R: */ +#define CpControl 1 /* R/W: */ +#define CpTTB 2 /* R/W: translation table base */ +#define CpDAC 3 /* R/W: domain access control */ +#define CpFSR 5 /* R/W: fault status */ +#define CpFAR 6 /* R/W: fault address */ +#define CpCacheCtl 7 /* W: */ +#define CpTLBops 8 /* W: TLB operations */ +#define CpRBops 9 /* W: Read Buffer operations */ +#define CpPID 13 /* R/W: Process ID Virtual Mapping */ +#define CpDebug 14 /* R/W: debug registers */ +#define CpTest 15 /* W: Test, Clock and Idle Control */ + +/* + * Coprocessors + */ +#define CpMMU 15 +#define CpPWR 15 + +/* + * CpControl bits + */ +#define CpCmmu 0x00000001 /* M: MMU enable */ +#define CpCalign 0x00000002 /* A: alignment fault enable */ +#define CpCDcache 0x00000004 /* C: instruction/data cache on */ +#define CpCwb 0x00000008 /* W: write buffer turned on */ +#define CpCi32 0x00000010 /* P: 32-bit programme space */ +#define CpCd32 0x00000020 /* D: 32-bit data space */ +#define CpCbe 0x00000080 /* B: big-endian operation */ +#define CpCsystem 0x00000100 /* S: system permission */ +#define CpCrom 0x00000200 /* R: ROM permission */ +#define CpCIcache 0x00001000 /* I: Instruction Cache on */ +#define CpCaltivec 0x00002000 /* X: alternative interrupt vectors */ + +/* + * MMU + */ +/* + * Small pages: + * L1: 12-bit index -> 4096 descriptors -> 16Kb + * L2: 8-bit index -> 256 descriptors -> 1Kb + * Each L2 descriptor has access permissions for 4 1Kb sub-pages. + * + * TTB + L1Tx gives address of L1 descriptor + * L1 descriptor gives PTBA + * PTBA + L2Tx gives address of L2 descriptor + * L2 descriptor gives PBA + */ +#define MmuSection (1<<20) +#define MmuLargePage (1<<16) +#define MmuSmallPage (1<<12) +#define MmuTTB(pa) ((pa) & ~0x3FFF) /* translation table base */ +#define MmuL1x(pa) (((pa)>>20) & 0xFFF) /* L1 table index */ +#define MmuPTBA(pa) ((pa) & ~0x3FF) /* page table base address */ +#define MmuL2x(pa) (((pa)>>12) & 0xFF) /* L2 table index */ +#define MmuPBA(pa) ((pa) & ~0xFFF) /* page base address */ +#define MmuSBA(pa) ((pa) & ~0xFFFFF) /* section base address */ + +#define MmuL1type 0x03 +#define MmuL1page 0x01 /* descriptor is for L2 pages */ +#define MmuL1section 0x02 /* descriptor is for section */ + +#define MmuL2invalid 0x000 +#define MmuL2large 0x001 /* large */ +#define MmuL2small 0x002 /* small */ +#define MmuWB 0x004 /* data goes through write buffer */ +#define MmuIDC 0x008 /* data placed in cache */ + +#define MmuDAC(d) (((d) & 0xF)<<5) /* L1 domain */ +#define MmuAP(i, v) ((v)<<(((i)*2)+4)) /* access permissions */ +#define MmuL1AP(v) MmuAP(3, (v)) +#define MmuL2AP(v) MmuAP(3, (v))|MmuAP(2, (v))|MmuAP(1, (v))|MmuAP(0, (v)) +#define MmuAPsro 0 /* supervisor ro if S|R */ +#define MmuAPsrw 1 /* supervisor rw */ +#define MmuAPuro 2 /* supervisor rw + user ro */ +#define MmuAPurw 3 /* supervisor rw + user rw */ diff --git a/os/cerf1110/mkfile b/os/cerf1110/mkfile new file mode 100644 index 00000000..693f3248 --- /dev/null +++ b/os/cerf1110/mkfile @@ -0,0 +1,101 @@ +<../../mkconfig +TKSTYLE=std + +#Configurable parameters + +CONF=cerf #default configuration +CONFLIST=cerf + +SYSTARG=$OSTARG +OBJTYPE=arm +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 + +KTZERO=0xC0008010 + +OBJ=\ + l.$O\ + clock.$O\ + dma.$O\ + fpi.$O\ + fpiarm.$O\ + fpimem.$O\ + main.$O\ + mmu.$O\ + trap.$O\ + $CONF.root.$O\ + $IP\ + $DEVS\ + $ETHERS\ + $LINKS\ + $PORT\ + $MISC\ + $OTHERS\ + +LIBNAMES=${LIBS:%=lib%.a} +LIBDIRS=$LIBS + +HFILES=\ + mem.h\ + dat.h\ + fns.h\ + io.h\ + ../sa1110/sa1110io.h\ + ../sa1110/fpi.h\ + +CFLAGS=-wFV -I$ROOT/Inferno/$OBJTYPE/include -I$ROOT/include -I$ROOT/libinterp -I../sa1110 +KERNDATE=`{$NDATE} + +default:V: i$CONF i$CONF.p9 + +install:V: $INSTALLDIR/i$CONF + +i$CONF: $OBJ $CONF.c $CONF.root.h $LIBNAMES i$CONF.p9 + $CC $CFLAGS '-DKERNDATE='$KERNDATE $CONF.c + $LD -s -o $target -H5 -T0xC0008010 -R4 -l $OBJ $CONF.$O $LIBFILES + +i$CONF.p9: $OBJ $CONF.c $CONF.root.h $LIBNAMES + $CC $CFLAGS '-DKERNDATE='$KERNDATE $CONF.c + $LD -o $target -T0xC0008010 -R4 -l $OBJ $CONF.$O $LIBFILES + +<../port/portmkfile + +%.$O: ../sa1110/%.c + $CC $CFLAGS -I. ../sa1110/$stem.c + +%.$O: ../sa1110/%.s + $AS -I. -I../sa1110 ../sa1110/$stem.s + +../init/$INIT.dis: ../init/$INIT.b + cd ../init; mk $INIT.dis + +clock.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h +devether.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h +devsapcm.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h +main.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h +trap.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h + +devether.$O $ETHERS: ../sa1110/etherif.h ../port/netif.h +$IP devip.$O: ../ip/ip.h +io.h:N: ../sa1110/sa1110io.h + +dummy:V: + +# to be moved to libinterp +bench.h:D: ../../module/bench.m + rm -f $target && limbo -a -I../../module ../../module/bench.m > $target +benchmod.h:D: ../../module/bench.m + rm -f $target && limbo -t Bench -I../../module ../../module/bench.m > $target +devbench.$O: bench.h benchmod.h + +devaudio.$O: devaudio.c + $CC $CFLAGS devaudio.c + +arch$CONF.$O: ../sa1110/etherif.h + +devuart.$O: ../sa1110/devuart.c + $CC $CFLAGS ../sa1110/devuart.c |
