ref: 7a3f0998a0ce7470d70c1a13bc4646abafdcc236
parent: 6dafa424805d128fcd08c71dca3e3abdc40aa6c6
author: aiju <aiju@phicode.de>
date: Wed Dec 24 05:21:51 EST 2014
added zynq kernel
--- /dev/null
+++ b/sys/src/9/zynq/dat.h
@@ -1,0 +1,196 @@
+typedef struct Conf Conf;
+typedef struct Confmem Confmem;
+typedef struct FPsave FPsave;
+typedef struct L1 L1;
+typedef struct Label Label;
+typedef struct Lock Lock;
+typedef struct KMap KMap;
+typedef struct MMMU MMMU;
+typedef struct Mach Mach;
+typedef struct Notsave Notsave;
+typedef struct Page Page;
+typedef struct Proc Proc;
+typedef struct PMMU PMMU;
+typedef u32int PTE;
+typedef struct Ureg Ureg;
+typedef struct ISAConf ISAConf;
+typedef uvlong Tval;
+
+#pragma incomplete Ureg
+
+#define MAXSYSARG 5 /* for mount(fd, mpt, flag, arg, srv) */
+
+#define AOUT_MAGIC (E_MAGIC)
+
+struct Lock
+{
+ ulong key;
+ u32int sr;
+ uintptr pc;
+ Proc* p;
+ Mach* m;
+ int isilock;
+};
+
+struct Label
+{
+ uintptr sp;
+ uintptr pc;
+};
+
+struct FPsave
+{
+ ulong exc, scr;
+ uchar regs[256];
+};
+
+/*
+ * FPsave.status
+ */
+enum
+{
+ FPinit,
+ FPactive,
+ FPinactive,
+ FPillegal = 0x100
+};
+
+struct Confmem
+{
+ uintptr base;
+ uintptr limit;
+ usize npage;
+ uintptr kbase;
+ uintptr klimit;
+};
+
+struct Conf
+{
+ ulong nmach; /* processors */
+ ulong nproc; /* processes */
+ Confmem mem[1]; /* physical memory */
+ ulong npage; /* total physical pages of memory */
+ usize upages; /* user page pool */
+ ulong copymode; /* 0 is copy on write, 1 is copy on reference */
+ ulong ialloc; /* max interrupt time allocation in bytes */
+ ulong pipeqsize; /* size in bytes of pipe queues */
+ ulong nimage; /* number of page cache image headers */
+ ulong nswap; /* number of swap pages */
+ int nswppo; /* max # of pageouts per segment pass */
+ int monitor;
+};
+
+/*
+ * things saved in the Proc structure during a notify
+ */
+struct Notsave {
+ int emptiness;
+};
+
+/*
+ * MMU stuff in proc
+ */
+#define NCOLOR 1
+
+struct PMMU
+{
+ L1 *l1;
+ Page *mmuused, *mmufree;
+
+ int nkmap;
+ Page *kmaptable;
+};
+
+#include "../port/portdat.h"
+
+struct L1
+{
+ Ref;
+ uintptr pa;
+ ulong *va;
+ L1 *next;
+};
+
+struct MMMU
+{
+ L1 l1;
+ L1 *l1free;
+ int nfree;
+ uchar asid;
+};
+
+struct Mach
+{
+ /* known to assembly */
+ int machno; /* physical id of processor */
+ uintptr splpc; /* pc of last caller to splhi */
+ Proc* proc; /* current process */
+ ulong excregs[3];
+ ulong cycleshi;
+ /* end of known to assembly */
+
+ int flushmmu; /* flush current proc mmu state */
+
+ 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;
+
+ Proc* readied; /* for runproc */
+ ulong schedticks; /* next forced context switch */
+
+ int cputype;
+ ulong delayloop;
+
+ /* stats */
+ int tlbfault;
+ int tlbpurge;
+ int pfault;
+ int cs;
+ int syscall;
+ int load;
+ int intr;
+ uvlong fastclock; /* last sampled value */
+ uvlong inidle; /* time spent in idlehands() */
+// ulong spuriousintr;
+ int lastintr;
+ int ilockdepth;
+ Perf perf; /* performance counters */
+
+
+ int cpumhz;
+ uvlong cpuhz; /* speed of cpu */
+ uvlong cyclefreq; /* Frequency of user readable cycle counter */
+
+ MMMU;
+
+ int stack[1];
+};
+
+struct ISAConf
+{
+ int dummy;
+ char *type;
+ ulong port;
+ int irq;
+};
+#define BUSUNKNOWN -1
+
+struct
+{
+ Lock;
+ int machs; /* bitmap of active CPUs */
+ int exiting; /* shutdown */
+ int ispanic; /* shutdown in response to a panic */
+}active;
+
+extern register Mach* m; /* R10 */
+extern register Proc* up; /* R9 */
+
+extern int normalprint;
+
+extern ulong *mpcore, *slcr;
+
+void nope(void);
+#define NOPE nope();
--- /dev/null
+++ b/sys/src/9/zynq/devarch.c
@@ -1,0 +1,391 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "../port/error.h"
+
+enum {
+ Qdir = 0,
+ Qtemp,
+ Qpl,
+ Qbase,
+
+ Qmax = 16,
+};
+
+static Dirtab archdir[Qmax] = {
+ ".", { Qdir, 0, QTDIR }, 0, 0555,
+ "temp", { Qtemp, 0}, 0, 0440,
+ "pl", { Qpl, 0 }, 0, 0660,
+};
+static int narchdir = Qbase;
+
+int temp = -128;
+ulong *devc;
+int dmadone;
+QLock pllock;
+enum { PLBUFSIZ = 8192 };
+uchar *plbuf;
+Rendez plinitr, pldoner, pldmar;
+
+enum {
+ DEVCTRL = 0,
+ DEVISTS = 0xc/4,
+ DEVMASK,
+ DEVSTS,
+ DMASRC = 0x18/4,
+ DMADST,
+ DMASRCL,
+ DMADSTL,
+ XADCCFG = 0x100/4,
+ XADCSTS,
+ XADCMASK,
+ XADCMSTS,
+ XADCCMD,
+ XADCREAD,
+ XADCMCTL,
+
+ FPGA0_CLK_CTRL = 0x170/4,
+};
+
+enum {
+ PROG = 1<<30,
+ DONE = 1<<2,
+ INITPE = 1<<1,
+ INIT = 1<<4,
+ DMADONE = 1<<13,
+};
+
+static void
+scram(void)
+{
+ splhi();
+ slcr[0x100/4] |= 1<<4;
+ slcr[0x104/4] |= 1<<4;
+ slcr[0x108/4] |= 1<<4;
+ slcr[DEVCTRL] &= ~PROG;
+ slcr[0x244/4] = 1<<4|1<<5;
+}
+
+static void
+xadcirq(Ureg *, void *)
+{
+ int v;
+ static int al, notfirst;
+
+ while((devc[XADCMSTS] & 1<<8) == 0){
+ v = ((u16int)devc[XADCREAD]) >> 4;
+ if(v == 0){
+ if(notfirst)
+ print("temperature sensor reads 0, shouldn't happen\n");
+ break;
+ }
+ notfirst = 1;
+ temp = v * 5040 / 4096 - 2732;
+ if(temp >= 800){
+ if(al == 0)
+ print("temperature exceeds 80 deg C\n");
+ al = 1;
+ }
+ if(temp <= 750)
+ al = 0;
+ if(temp >= 900){
+ print("chip temperature exceeds 90 deg C, shutting down");
+ scram();
+ }
+ }
+ devc[XADCSTS] = -1;
+}
+
+static void
+xadctimer(void)
+{
+ devc[XADCCMD] = 1<<26 | 0<<16;
+}
+
+static void
+xadcinit(void)
+{
+ int i;
+ int x;
+
+ devc = vmap(DEVC_BASE, 0x11C);
+ devc[XADCMCTL] |= 1<<4;
+ devc[XADCMCTL] &= ~(1<<4);
+ devc[XADCCMD] = 0x08030000;
+ for(i = 0; i < 15; i++)
+ devc[XADCCMD] = 0;
+ while((devc[XADCMSTS] & 1<<10) == 0)
+ ;
+ while((devc[XADCMSTS] & 1<<8) == 0){
+ x = devc[XADCREAD];
+ USED(x);
+ }
+ devc[XADCCFG] = 0x80001114;
+ devc[XADCMASK] = ~(1<<8);
+ devc[XADCSTS] = -1;
+ intrenable(XADCIRQ, xadcirq, nil, LEVEL, "xadc");
+ addclock0link(xadctimer, XADCINTERVAL);
+}
+
+static int
+isplinit(void *)
+{
+ return devc[DEVSTS] & INIT;
+}
+
+static int
+ispldone(void *)
+{
+ return devc[DEVISTS] & DONE;
+}
+
+static int
+isdmadone(void *)
+{
+ return dmadone;
+}
+
+static void
+plirq(Ureg *, void *)
+{
+ ulong fl;
+
+ fl = devc[DEVISTS];
+ if((fl & INITPE) != 0)
+ wakeup(&plinitr);
+ if((fl & DONE) != 0){
+ slcr[0x900/4] = 0xf;
+ slcr[0x240/4] = 0;
+ print("DONE!\n");
+ devc[DEVMASK] |= DONE;
+ wakeup(&pldoner);
+ }
+ if((fl & DMADONE) != 0){
+ dmadone++;
+ wakeup(&pldmar);
+ }
+ devc[DEVISTS] = fl;
+}
+
+static void
+plinit(void)
+{
+ Physseg seg;
+
+ devc[DEVCTRL] &= ~(PROG|1<<25);
+ devc[DEVCTRL] |= 3<<26|PROG;
+ devc[DEVISTS] = -1;
+ devc[DEVMASK] = ~(DONE|INITPE|DMADONE);
+ intrenable(DEVCIRQ, plirq, nil, LEVEL, "pl");
+
+ slcr[FPGA0_CLK_CTRL] = 1<<20 | 10<<8;
+
+ memset(&seg, 0, sizeof seg);
+ seg.attr = SG_PHYSICAL;
+ seg.name = "axi";
+ seg.pa = 0x40000000;
+ seg.size = 0x8000000;
+ addphysseg(&seg);
+}
+
+static void
+plconf(void)
+{
+ if(!canqlock(&pllock))
+ error(Einuse);
+ slcr[0x240/4] = 0xf;
+ slcr[0x900/4] = 0xa;
+ dmadone = 1;
+ devc[DEVISTS] = DONE|INITPE|DMADONE;
+ devc[DEVCTRL] |= PROG;
+ devc[DEVCTRL] &= ~PROG;
+ devc[DEVMASK] &= ~DONE;
+ devc[DEVCTRL] |= PROG;
+ sleep(&plinitr, isplinit, nil);
+ plbuf = smalloc(PLBUFSIZ);
+}
+
+static long
+plwrite(uintptr pa, long n)
+{
+ long w;
+
+ w = n >> 2;
+ sleep(&pldmar, isdmadone, nil);
+ dmadone = 0;
+ coherence();
+ devc[DMASRC] = pa;
+ devc[DMADST] = -1;
+ devc[DMASRCL] = w;
+ devc[DMADSTL] = 0;
+ return n;
+}
+
+static long
+plcopy(uchar *d, long n)
+{
+ long ret;
+ ulong nn;
+ uintptr pa;
+
+ if((n & 3) != 0 || n <= 0)
+ error(Eshort);
+ ret = n;
+ pa = PADDR(plbuf);
+ while(n > 0){
+ if(n > PLBUFSIZ)
+ nn = PLBUFSIZ;
+ else
+ nn = n;
+ memmove(plbuf, d, nn);
+ cleandse(plbuf, plbuf + nn);
+ clean2pa(pa, pa + nn);
+ n -= plwrite(pa, nn);
+ }
+ return ret;
+}
+
+static long
+userdma(void *a, long n, long (*f)(uintptr, long))
+{
+ ulong s;
+ void *va;
+ uintptr pa;
+ long off, nn, ret;
+
+ evenaddr((uintptr) a);
+ if((n & 3) != 0)
+ error(Eshort);
+
+ ret = n;
+ while(n > 0){
+ off = (uintptr)a & BY2PG - 1;
+ va = (void *) ((uintptr)a & ~(BY2PG - 1));
+ s = splhi();
+ while(pa = palookur(va), (pa & 1) != 0){
+ splx(s);
+ if(fault(pa, 1) < 0)
+ error(Egreg);
+ s = splhi();
+ }
+ if(off + n >= BY2PG)
+ nn = BY2PG - off;
+ else
+ nn = n;
+ pa = (pa & ~(BY2PG - 1)) + off;
+ cleandse((char *) a + off, (char*) a + off + nn);
+ clean2pa(pa, pa + nn);
+ n -= f(pa, nn);
+ splx(s);
+ a = (char *) va + BY2PG;
+ }
+ return ret;
+}
+
+void
+archinit(void)
+{
+ slcr[2] = 0xDF0D;
+ xadcinit();
+ plinit();
+}
+
+static long
+archread(Chan *c, void *a, long n, vlong offset)
+{
+ char buf[64];
+
+ switch((ulong)c->qid.path){
+ case Qdir:
+ return devdirread(c, a, n, archdir, narchdir, devgen);
+ case Qtemp:
+ snprint(buf, sizeof(buf), "%d.%d\n", temp/10, temp%10);
+ return readstr(offset, a, n, buf);
+ case Qpl:
+ sleep(&pldoner, ispldone, nil);
+ return 0;
+ default:
+ error(Egreg);
+ return -1;
+ }
+}
+
+static long
+archwrite(Chan *c, void *a, long n, vlong offset)
+{
+ switch((ulong)c->qid.path){
+ case Qpl:
+ return plcopy(a, n);
+ default:
+ error(Egreg);
+ return -1;
+ }
+}
+
+Walkqid*
+archwalk(Chan* c, Chan *nc, char** name, int nname)
+{
+ return devwalk(c, nc, name, nname, archdir, narchdir, devgen);
+}
+
+static int
+archstat(Chan* c, uchar* dp, int n)
+{
+ return devstat(c, dp, n, archdir, narchdir, devgen);
+}
+
+static Chan*
+archopen(Chan* c, int omode)
+{
+ devopen(c, omode, archdir, narchdir, devgen);
+ if((ulong)c->qid.path == Qpl && c->mode == OWRITE)
+ plconf();
+ return c;
+}
+
+static void
+archclose(Chan* c)
+{
+ if((ulong)c->qid.path == Qpl && c->mode == OWRITE){
+ /* cleandse(plbuf, plbuf + plbufn);
+ clean2pa(PADDR(plbuf), PADDR(plbuf) + plbufn);
+ plwrite(PADDR(plbuf), 4096);
+ plwrite(PADDR(plbuf) + 4096, plbufn - 4096);
+ plbufn = 0;*/
+ free(plbuf);
+ plbuf = nil;
+ qunlock(&pllock);
+ }
+}
+
+static Chan*
+archattach(char* spec)
+{
+ return devattach('P', spec);
+}
+
+Dev archdevtab = {
+ 'P',
+ "arch",
+
+ devreset,
+ devinit,
+ devshutdown,
+ archattach,
+ archwalk,
+ archstat,
+ archopen,
+ devcreate,
+ archclose,
+ archread,
+ devbread,
+ archwrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
+
--- /dev/null
+++ b/sys/src/9/zynq/devether.c
@@ -1,0 +1,517 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "pool.h"
+#include "ureg.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+
+#include "etherif.h"
+
+static Ether *etherxx[MaxEther];
+
+Chan*
+etherattach(char* spec)
+{
+ ulong ctlrno;
+ char *p;
+ Chan *chan;
+
+ ctlrno = 0;
+ if(spec && *spec){
+ ctlrno = strtoul(spec, &p, 0);
+ if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
+ error(Ebadarg);
+ }
+ if(etherxx[ctlrno] == 0)
+ error(Enodev);
+
+ chan = devattach('l', spec);
+ if(waserror()){
+ chanfree(chan);
+ nexterror();
+ }
+ chan->dev = ctlrno;
+ if(etherxx[ctlrno]->attach)
+ etherxx[ctlrno]->attach(etherxx[ctlrno]);
+ poperror();
+ return chan;
+}
+
+static Walkqid*
+etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
+{
+ return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
+}
+
+static int
+etherstat(Chan* chan, uchar* dp, int n)
+{
+ return netifstat(etherxx[chan->dev], chan, dp, n);
+}
+
+static Chan*
+etheropen(Chan* chan, int omode)
+{
+ return netifopen(etherxx[chan->dev], chan, omode);
+}
+
+static Chan*
+ethercreate(Chan*, char*, int, ulong)
+{
+ error(Eperm);
+ return 0;
+}
+
+static void
+etherclose(Chan* chan)
+{
+ netifclose(etherxx[chan->dev], chan);
+}
+
+static long
+etherread(Chan* chan, void* buf, long n, vlong off)
+{
+ Ether *ether;
+ ulong offset = off;
+
+ ether = etherxx[chan->dev];
+ if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
+ /*
+ * With some controllers it is necessary to reach
+ * into the chip to extract statistics.
+ */
+ if(NETTYPE(chan->qid.path) == Nifstatqid)
+ return ether->ifstat(ether, buf, n, offset);
+ else if(NETTYPE(chan->qid.path) == Nstatqid)
+ ether->ifstat(ether, buf, 0, offset);
+ }
+
+ return netifread(ether, chan, buf, n, offset);
+}
+
+static Block*
+etherbread(Chan* chan, long n, ulong offset)
+{
+ return netifbread(etherxx[chan->dev], chan, n, offset);
+}
+
+static int
+etherwstat(Chan* chan, uchar* dp, int n)
+{
+ return netifwstat(etherxx[chan->dev], chan, dp, n);
+}
+
+static void
+etherrtrace(Netfile* f, Etherpkt* pkt, int len)
+{
+ int i, n;
+ Block *bp;
+
+ if(qwindow(f->in) <= 0)
+ return;
+ if(len > 58)
+ n = 58;
+ else
+ n = len;
+ bp = iallocb(64);
+ if(bp == nil)
+ return;
+ memmove(bp->wp, pkt->d, n);
+ i = TK2MS(MACHP(0)->ticks);
+ bp->wp[58] = len>>8;
+ bp->wp[59] = len;
+ bp->wp[60] = i>>24;
+ bp->wp[61] = i>>16;
+ bp->wp[62] = i>>8;
+ bp->wp[63] = i;
+ bp->wp += 64;
+ qpass(f->in, bp);
+}
+
+Block*
+etheriq(Ether* ether, Block* bp, int fromwire)
+{
+ Etherpkt *pkt;
+ ushort type;
+ int len, multi, tome, fromme;
+ Netfile **ep, *f, **fp, *fx;
+ Block *xbp;
+
+ ether->inpackets++;
+
+ pkt = (Etherpkt*)bp->rp;
+ len = BLEN(bp);
+ type = (pkt->type[0]<<8)|pkt->type[1];
+ fx = 0;
+ ep = ðer->f[Ntypes];
+
+ multi = pkt->d[0] & 1;
+ /* check for valid multicast addresses */
+ if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
+ if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
+ if(fromwire){
+ freeb(bp);
+ bp = 0;
+ }
+ return bp;
+ }
+ }
+
+ /* is it for me? */
+ tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
+ fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
+
+ /*
+ * Multiplex the packet to all the connections which want it.
+ * If the packet is not to be used subsequently (fromwire != 0),
+ * attempt to simply pass it into one of the connections, thereby
+ * saving a copy of the data (usual case hopefully).
+ */
+ for(fp = ether->f; fp < ep; fp++){
+ if(f = *fp)
+ if(f->type == type || f->type < 0)
+ if(tome || multi || f->prom){
+ /* Don't want to hear bridged packets */
+ if(f->bridge && !fromwire && !fromme)
+ continue;
+ if(!f->headersonly){
+ if(fromwire && fx == 0)
+ fx = f;
+ else if(xbp = iallocb(len)){
+ memmove(xbp->wp, pkt, len);
+ xbp->wp += len;
+ if(qpass(f->in, xbp) < 0) {
+ // print("soverflow for f->in\n");
+ ether->soverflows++;
+ }
+ }
+ else {
+ // print("soverflow iallocb\n");
+ ether->soverflows++;
+ }
+ }
+ else
+ etherrtrace(f, pkt, len);
+ }
+ }
+
+ if(fx){
+ if(qpass(fx->in, bp) < 0) {
+ // print("soverflow for fx->in\n");
+ ether->soverflows++;
+ }
+ return 0;
+ }
+ if(fromwire){
+ freeb(bp);
+ return 0;
+ }
+
+ return bp;
+}
+
+static int
+etheroq(Ether* ether, Block* bp)
+{
+ int len, loopback;
+ Etherpkt *pkt;
+
+ ether->outpackets++;
+
+ /*
+ * Check if the packet has to be placed back onto the input queue,
+ * i.e. if it's a loopback or broadcast packet or the interface is
+ * in promiscuous mode.
+ * If it's a loopback packet indicate to etheriq that the data isn't
+ * needed and return, etheriq will pass-on or free the block.
+ * To enable bridging to work, only packets that were originated
+ * by this interface are fed back.
+ */
+ pkt = (Etherpkt*)bp->rp;
+ len = BLEN(bp);
+ loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
+ if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom)
+ if(etheriq(ether, bp, loopback) == 0)
+ return len;
+
+ qbwrite(ether->oq, bp);
+ if(ether->transmit != nil)
+ ether->transmit(ether);
+ return len;
+}
+
+static long
+etherwrite(Chan* chan, void* buf, long n, vlong)
+{
+ Ether *ether;
+ Block *bp;
+ int nn, onoff;
+ Cmdbuf *cb;
+
+ ether = etherxx[chan->dev];
+ if(NETTYPE(chan->qid.path) != Ndataqid) {
+ nn = netifwrite(ether, chan, buf, n);
+ if(nn >= 0)
+ return nn;
+ cb = parsecmd(buf, n);
+ if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
+ if(cb->nf <= 1)
+ onoff = 1;
+ else
+ onoff = atoi(cb->f[1]);
+ qnoblock(ether->oq, onoff);
+ free(cb);
+ return n;
+ }
+ free(cb);
+ if(ether->ctl!=nil)
+ return ether->ctl(ether,buf,n);
+
+ error(Ebadctl);
+ }
+
+ if(n > ether->maxmtu)
+ error(Etoobig);
+ if(n < ether->minmtu)
+ error(Etoosmall);
+
+ bp = allocb(n);
+ if(waserror()){
+ freeb(bp);
+ nexterror();
+ }
+ memmove(bp->rp, buf, n);
+ memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
+ poperror();
+ bp->wp += n;
+
+ return etheroq(ether, bp);
+}
+
+static long
+etherbwrite(Chan* chan, Block* bp, ulong)
+{
+ Ether *ether;
+ long n;
+
+ n = BLEN(bp);
+ if(NETTYPE(chan->qid.path) != Ndataqid){
+ if(waserror()) {
+ freeb(bp);
+ nexterror();
+ }
+ n = etherwrite(chan, bp->rp, n, 0);
+ poperror();
+ freeb(bp);
+ return n;
+ }
+ ether = etherxx[chan->dev];
+
+ if(n > ether->maxmtu){
+ freeb(bp);
+ error(Etoobig);
+ }
+ if(n < ether->minmtu){
+ freeb(bp);
+ error(Etoosmall);
+ }
+
+ return etheroq(ether, bp);
+}
+
+static struct {
+ char* type;
+ int (*reset)(Ether*);
+} cards[MaxEther+1];
+
+void
+addethercard(char* t, int (*r)(Ether*))
+{
+ static int ncard;
+
+ if(ncard == MaxEther)
+ panic("too many ether cards");
+ cards[ncard].type = t;
+ cards[ncard].reset = r;
+ ncard++;
+}
+
+int
+parseether(uchar *to, char *from)
+{
+ char nip[4];
+ char *p;
+ int i;
+
+ p = from;
+ for(i = 0; i < Eaddrlen; i++){
+ if(*p == 0)
+ return -1;
+ nip[0] = *p++;
+ if(*p == 0)
+ return -1;
+ nip[1] = *p++;
+ nip[2] = 0;
+ to[i] = strtoul(nip, 0, 16);
+ if(*p == ':')
+ p++;
+ }
+ return 0;
+}
+
+static Ether*
+etherprobe(int cardno, int ctlrno)
+{
+ int i, lg;
+ ulong mb, bsz;
+ Ether *ether;
+ char buf[128], name[32];
+
+ ether = malloc(sizeof(Ether));
+ if(ether == nil){
+ print("etherprobe: no memory for Ether\n");
+ return nil;
+ }
+ memset(ether, 0, sizeof(Ether));
+ ether->ctlrno = ctlrno;
+ ether->mbps = 10;
+ ether->minmtu = ETHERMINTU;
+ ether->maxmtu = ETHERMAXTU;
+
+ if(cardno >= MaxEther || cards[cardno].type == nil){
+ free(ether);
+ return nil;
+ }
+ if(cards[cardno].reset(ether) < 0){
+ free(ether);
+ return nil;
+ }
+
+ snprint(name, sizeof(name), "ether%d", ctlrno);
+
+ intrenable(ether->irq, ether->interrupt, ether, ether->irqlevel, name);
+
+ i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
+ ctlrno, cards[cardno].type, ether->mbps, ether->port, ether->irq);
+ i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
+ ether->ea[0], ether->ea[1], ether->ea[2],
+ ether->ea[3], ether->ea[4], ether->ea[5]);
+ sprint(buf+i, "\n");
+ print(buf);
+
+ /* compute log10(ether->mbps) into lg */
+ for(lg = 0, mb = ether->mbps; mb >= 10; lg++)
+ mb /= 10;
+ if (lg > 0)
+ lg--;
+ if (lg > 14) /* 2^(14+17) = 2³¹ */
+ lg = 14;
+ /* allocate larger output queues for higher-speed interfaces */
+ bsz = 1UL << (lg + 17); /* 2¹⁷ = 128K, bsz = 2ⁿ × 128K */
+ while (bsz > mainmem->maxsize / 8 && bsz > 128*1024)
+ bsz /= 2;
+
+ netifinit(ether, name, Ntypes, bsz);
+ if(ether->oq == nil) {
+ ether->oq = qopen(bsz, Qmsg, 0, 0);
+ ether->limit = bsz;
+ }
+ if(ether->oq == nil)
+ panic("etherreset %s: can't allocate output queue of %ld bytes", name, bsz);
+ ether->alen = Eaddrlen;
+ memmove(ether->addr, ether->ea, Eaddrlen);
+ memset(ether->bcast, 0xFF, Eaddrlen);
+
+ return ether;
+}
+
+static void
+etherreset(void)
+{
+ Ether *ether;
+ int cardno, ctlrno;
+
+ for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
+ if((ether = etherprobe(-1, ctlrno)) == nil)
+ continue;
+ etherxx[ctlrno] = ether;
+ }
+
+ cardno = ctlrno = 0;
+ while(cards[cardno].type != nil && ctlrno < MaxEther){
+ if(etherxx[ctlrno] != nil){
+ ctlrno++;
+ continue;
+ }
+ if((ether = etherprobe(cardno, ctlrno)) == nil){
+ cardno++;
+ continue;
+ }
+ etherxx[ctlrno] = ether;
+ ctlrno++;
+ }
+}
+
+static void
+ethershutdown(void)
+{
+ Ether *ether;
+ int i;
+
+ for(i = 0; i < MaxEther; i++){
+ ether = etherxx[i];
+ if(ether == nil)
+ continue;
+ if(ether->shutdown == nil) {
+ print("#l%d: no shutdown function\n", i);
+ continue;
+ }
+ (*ether->shutdown)(ether);
+ }
+}
+
+
+#define POLY 0xedb88320
+
+/* really slow 32 bit crc for ethers */
+ulong
+ethercrc(uchar *p, int len)
+{
+ int i, j;
+ ulong crc, b;
+
+ crc = 0xffffffff;
+ for(i = 0; i < len; i++){
+ b = *p++;
+ for(j = 0; j < 8; j++){
+ crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
+ b >>= 1;
+ }
+ }
+ return crc;
+}
+
+Dev etherdevtab = {
+ 'l',
+ "ether",
+
+ etherreset,
+ devinit,
+ ethershutdown,
+ etherattach,
+ etherwalk,
+ etherstat,
+ etheropen,
+ ethercreate,
+ etherclose,
+ etherread,
+ etherbread,
+ etherwrite,
+ etherbwrite,
+ devremove,
+ etherwstat,
+};
--- /dev/null
+++ b/sys/src/9/zynq/devqspi.c
@@ -1,0 +1,275 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "../port/error.h"
+
+enum {
+ QSPIDIV = 1,
+ QSPISIZ = 1<<24,
+};
+
+enum {
+ CONF,
+ INTSTAT,
+ INTEN,
+ INTDIS,
+ INTMASK,
+ SPIEN,
+ DELAY,
+ TXD0,
+ RXD,
+ IDLE,
+ TXTHRES,
+ RXTHRES,
+ TXD1 = 0x80/4,
+ TXD2,
+ TXD3,
+ LQSPICFG = 0xA0/4,
+};
+
+enum {
+ TXFULL = 1<<3,
+ TXNFULL = 1<<2,
+ RXNEMPTY = 1<<4,
+ STARTCOM = 1<<16,
+};
+
+enum {
+ Qdir = 0,
+ Qboot,
+ Qbase,
+
+ Qmax = 16,
+};
+
+static ulong *qspi;
+static QLock qspil;
+
+static Dirtab qspidir[Qmax] = {
+ ".", { Qdir, 0, QTDIR }, 0, 0555,
+ "boot", { Qboot, 0}, 65536, 0640,
+};
+static int nqspidir = Qbase;
+
+static ulong
+qspicmd(int n, ulong d)
+{
+ while((qspi[INTSTAT] & TXNFULL) == 0)
+ ;
+ if(n == 4)
+ qspi[TXD0] = d;
+ else
+ qspi[TXD1 - 1 + n] = d;
+ qspi[CONF] |= STARTCOM;
+ while((qspi[INTSTAT] & (TXNFULL|RXNEMPTY)) != (TXNFULL|RXNEMPTY))
+ ;
+ return qspi[RXD];
+}
+
+static void
+qspiinit(void)
+{
+ static int done;
+
+ if(done)
+ return;
+ qspi = vmap(QSPI_BASE, 0x100);
+ qspi[LQSPICFG] &= ~(1<<31);
+ qspi[CONF] = 1<<31 | 1<<19 | 1<<15 | 1<<14 | 1<<10 | 3<<6 | QSPIDIV<<3 | 1;
+ qspi[SPIEN] = 1;
+}
+
+static void
+qspisel(int sel)
+{
+ if(sel)
+ qspi[CONF] &= ~(1<<10);
+ else
+ qspi[CONF] |= 1<<10;
+}
+
+static void
+waitbusy(void)
+{
+ ulong d;
+
+ for(;;){
+ qspisel(1);
+ d = qspicmd(2, 0x05);
+ qspisel(0);
+ if((d & 1<<24) == 0)
+ break;
+ tsleep(&up->sleep, return0, nil, 1);
+ }
+}
+
+static ulong
+doread(uvlong addr, void *a, ulong n)
+{
+ ulong d, *aa, nn, ret;
+
+ if(addr >= QSPISIZ)
+ return 0;
+ if(addr + n > QSPISIZ)
+ n = QSPISIZ - addr;
+ evenaddr((uintptr) a);
+ qspisel(1);
+ qspicmd(4, 0x6B | addr << 8);
+ qspicmd(1, 0);
+ ret = n;
+ aa = a;
+ while(n > 0){
+ d = qspicmd(4, 0);
+ if(n >= 4){
+ *aa++ = d;
+ n -= 4;
+ }else{
+ memmove(aa, (char*) &d + 4 - n, n);
+ break;
+ }
+ }
+ qspisel(0);
+ return ret;
+}
+
+static ulong
+dowrite(uvlong addr, void *a, ulong n)
+{
+ ulong *aa, ret, nn;
+
+ if(addr >= QSPISIZ)
+ return 0;
+ if(addr + n > QSPISIZ)
+ n = QSPISIZ - addr;
+ evenaddr((uintptr) a);
+ ret = n;
+ aa = a;
+ while(n > 0){
+ qspisel(1);
+ qspicmd(1, 6);
+ qspisel(0);
+ qspisel(1);
+ qspicmd(4, 0x32 | addr << 8);
+ if(n > 256)
+ nn = 256;
+ else
+ nn = n;
+ n -= nn;
+ addr += nn;
+ while(nn > 0)
+ if(nn >= 4){
+ qspicmd(4, *aa++);
+ nn -= 4;
+ }else{
+ qspicmd(n, *aa);
+ break;
+ }
+ qspisel(0);
+ waitbusy();
+ }
+ return ret;
+}
+
+static void
+doerase(ulong addr)
+{
+ qspisel(1);
+ qspicmd(1, 6);
+ qspisel(0);
+ qspisel(1);
+ qspicmd(4, 0xD8 | addr << 8);
+ qspisel(0);
+ waitbusy();
+}
+
+static Walkqid*
+qspiwalk(Chan* c, Chan *nc, char** name, int nname)
+{
+ return devwalk(c, nc, name, nname, qspidir, nqspidir, devgen);
+}
+
+static int
+qspistat(Chan* c, uchar* dp, int n)
+{
+ return devstat(c, dp, n, qspidir, nqspidir, devgen);
+}
+
+static Chan*
+qspiopen(Chan* c, int omode)
+{
+ devopen(c, omode, qspidir, nqspidir, devgen);
+ if(c->qid.path == Qboot){
+ qlock(&qspil);
+ if((omode & OTRUNC) != 0)
+ doerase(0);
+ }
+ return c;
+}
+
+static void
+qspiclose(Chan* c)
+{
+ if(c->qid.path == Qboot)
+ qunlock(&qspil);
+}
+
+static long
+qspiread(Chan *c, void *a, long n, vlong offset)
+{
+ char buf[64];
+
+ switch((ulong)c->qid.path){
+ case Qdir:
+ return devdirread(c, a, n, qspidir, nqspidir, devgen);
+ case Qboot:
+ return doread(offset, a, n);
+ default:
+ error(Egreg);
+ return -1;
+ }
+}
+
+static long
+qspiwrite(Chan *c, void *a, long n, vlong offset)
+{
+ switch((ulong)c->qid.path){
+ case Qboot:
+ return dowrite(offset, a, n);
+ default:
+ error(Egreg);
+ return -1;
+ }
+}
+
+static Chan*
+qspiattach(char* spec)
+{
+ qspiinit();
+ return devattach('Q', spec);
+}
+
+Dev qspidevtab = {
+ 'Q',
+ "qspi",
+
+ devreset,
+ devinit,
+ devshutdown,
+ qspiattach,
+ qspiwalk,
+ qspistat,
+ qspiopen,
+ devcreate,
+ qspiclose,
+ qspiread,
+ devbread,
+ qspiwrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};
+
--- /dev/null
+++ b/sys/src/9/zynq/etherif.h
@@ -1,0 +1,40 @@
+enum {
+ MaxEther = 64,
+ Ntypes = 8,
+};
+
+typedef struct Ether Ether;
+struct Ether {
+
+ int ctlrno;
+ int minmtu;
+ int maxmtu;
+ uchar ea[Eaddrlen];
+
+ int irq, irqlevel;
+ uintptr port;
+
+ void (*attach)(Ether*); /* filled in by reset routine */
+ void (*detach)(Ether*);
+ void (*transmit)(Ether*);
+ void (*interrupt)(Ureg*, void*);
+ long (*ifstat)(Ether*, void*, long, ulong);
+ long (*ctl)(Ether*, void*, long); /* custom ctl messages */
+ void (*power)(Ether*, int); /* power on/off */
+ void (*shutdown)(Ether*); /* shutdown hardware before reboot */
+ void *ctlr;
+
+ Queue* oq;
+
+ Netif;
+};
+
+extern Block* etheriq(Ether*, Block*, int);
+extern void addethercard(char*, int(*)(Ether*));
+extern ulong ethercrc(uchar*, int);
+extern int parseether(uchar*, char*);
+
+#define NEXT(x, l) (((x)+1)%(l))
+#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1)
+#define HOWMANY(x, y) (((x)+((y)-1))/(y))
+#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y))
--- /dev/null
+++ b/sys/src/9/zynq/etherzynq.c
@@ -1,0 +1,380 @@
+#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"
+
+#define Rbsz ROUNDUP(sizeof(Etherpkt)+16, 64)
+
+enum {
+ RXRING = 0x200,
+ TXRING = 0x200,
+ Linkdelay = 500,
+ MDC_DIV = 6,
+};
+
+enum {
+ NET_CTRL,
+ NET_CFG,
+ NET_STATUS,
+ DMA_CFG = 4,
+ TX_STATUS,
+ RX_QBAR,
+ TX_QBAR,
+ RX_STATUS,
+ INTR_STATUS,
+ INTR_EN,
+ INTR_DIS,
+ INTR_MASK,
+ PHY_MAINT,
+ RX_PAUSEQ,
+ TX_PAUSEQ,
+ HASH_BOT = 32,
+ HASH_TOP,
+ SPEC_ADDR1_BOT,
+ SPEC_ADDR1_TOP,
+};
+
+enum {
+ MDCTRL,
+ MDSTATUS,
+ MDID1,
+ MDID2,
+ MDAUTOADV,
+ MDAUTOPART,
+ MDAUTOEX,
+ MDAUTONEXT,
+ MDAUTOLINK,
+ MDGCTRL,
+ MDGSTATUS,
+ MDPHYCTRL = 0x1f,
+};
+
+enum {
+ /* NET_CTRL */
+ RXEN = 1<<2,
+ TXEN = 1<<3,
+ MDEN = 1<<4,
+ STARTTX = 1<<9,
+ /* NET_CFG */
+ SPEED = 1<<0,
+ FDEN = 1<<1,
+ RX1536EN = 1<<8,
+ GIGE_EN = 1<<10,
+ RXCHKSUMEN = 1<<24,
+ /* NET_STATUS */
+ PHY_IDLE = 1<<2,
+ /* DMA_CFG */
+ TXCHKSUMEN = 1<<11,
+ /* TX_STATUS */
+ TXCOMPL = 1<<5,
+ /* INTR_{EN,DIS} */
+ MGMTDONE = 1<<0,
+ RXCOMPL = 1<<1,
+ RXUSED = 1<<2,
+ TXUNDER = 1<<4,
+ RXOVER = 1<<10,
+ /* MDCTRL */
+ MDRESET = 1<<15,
+ AUTONEG = 1<<12,
+ FULLDUP = 1<<8,
+ /* MDSTATUS */
+ LINK = 1<<2,
+ /* MDGSTATUS */
+ RECVOK = 3<<12,
+};
+
+enum {
+ RxUsed = 1,
+ TxUsed = 1<<31,
+ FrameEnd = 1<<15,
+};
+
+typedef struct Ctlr Ctlr;
+
+struct Ctlr {
+ ulong *r;
+ Rendez phy;
+ int phyaddr;
+ int rxconsi, rxprodi, txi;
+ ulong *rxr, *txr;
+ Block **rxs, **txs;
+ Lock txlock;
+ int attach;
+};
+
+static int
+phyidle(void *v)
+{
+ return ((Ctlr*)v)->r[NET_STATUS] & PHY_IDLE;
+}
+
+static void
+mdwrite(Ctlr *c, int r, u16int v)
+{
+ sleep(&c->phy, phyidle, c);
+ c->r[PHY_MAINT] = 1<<30 | 1<<28 | 1<<17 | c->phyaddr << 23 | r << 18 | v;
+ sleep(&c->phy, phyidle, c);
+}
+
+static u16int
+mdread(Ctlr *c, int r)
+{
+ sleep(&c->phy, phyidle, c);
+ c->r[PHY_MAINT] = 1<<30 | 1<< 29 | 1<<17 | c->phyaddr << 23 | r << 18;
+ sleep(&c->phy, phyidle, c);
+ return c->r[PHY_MAINT];
+}
+
+static void
+ethproc(void *ved)
+{
+ Ether *edev;
+ Ctlr *c;
+ char *sp, *dpl;
+ u16int v;
+
+ edev = ved;
+ c = edev->ctlr;
+ mdwrite(c, MDCTRL, AUTONEG);
+ for(;;){
+ if((mdread(c, MDSTATUS) & LINK) == 0){
+ edev->link = 0;
+ print("eth: no link\n");
+ while((mdread(c, MDSTATUS) & LINK) == 0)
+ tsleep(&up->sleep, return0, nil, Linkdelay);
+ }
+ v = mdread(c, MDPHYCTRL);
+ if((v & 0x40) != 0){
+ sp = "1000BASE-T";
+ while((mdread(c, MDGSTATUS) & RECVOK) != RECVOK)
+ ;
+ edev->mbps = 1000;
+ c->r[NET_CFG] |= GIGE_EN;
+ }else if((v & 0x20) != 0){
+ sp = "100BASE-TX";
+ edev->mbps = 100;
+ c->r[NET_CFG] = NET_CFG & ~GIGE_EN | SPEED;
+ }else if((v & 0x10) != 0){
+ sp = "10BASE-T";
+ edev->mbps = 10;
+ c->r[NET_CFG] = NET_CFG & ~(GIGE_EN | SPEED);
+ }else
+ sp = "???";
+ if((v & 0x08) != 0){
+ dpl = "full";
+ c->r[NET_CFG] |= FDEN;
+ }else{
+ dpl = "half";
+ c->r[NET_CFG] &= ~FDEN;
+ }
+ edev->link = 1;
+ print("eth: %s %s duplex link\n", sp, dpl);
+ while((mdread(c, MDSTATUS) & LINK) != 0)
+ tsleep(&up->sleep, return0, nil, Linkdelay);
+ }
+}
+
+static int
+replenish(Ctlr *c)
+{
+ Block *bp;
+ int i;
+ ulong *r;
+
+ while(c->rxprodi != c->rxconsi){
+ i = c->rxprodi;
+ bp = iallocb(Rbsz);
+ if(bp == nil){
+ print("eth: out of memory for receive buffers\n");
+ return -1;
+ }
+ c->rxs[i] = bp;
+ r = &c->rxr[2 * i];
+ r[0] = RxUsed | PADDR(bp->rp);
+ if(i == RXRING - 1)
+ r[0] |= 2;
+ r[1] = 0;
+ cleandse(bp->base, bp->lim);
+ clean2pa(PADDR(bp->base), PADDR(bp->lim));
+ r[0] &= ~RxUsed;
+ c->rxprodi = (c->rxprodi + 1) & (RXRING - 1);
+ }
+ return 0;
+}
+
+static void
+ethrx(Ether *edev)
+{
+ Ctlr *c;
+ ulong *r;
+ Block *bp;
+
+ c = edev->ctlr;
+// print("rx! %p %p\n", PADDR(&c->rxr[2 * c->rxconsi]), c->r[RX_QBAR]);
+ for(;;){
+ r = &c->rxr[2 * c->rxconsi];
+ if((r[0] & RxUsed) == 0)
+ break;
+ if((r[1] & FrameEnd) == 0)
+ print("eth: partial frame received -- shouldn't happen\n");
+ bp = c->rxs[c->rxconsi];
+ bp->wp = bp->rp + (r[1] & 0x1fff);
+ invaldse(bp->rp, bp->wp);
+ inval2pa(PADDR(bp->rp), PADDR(bp->wp));
+ etheriq(edev, bp, 1);
+ c->rxconsi = (c->rxconsi + 1) & (RXRING - 1);
+ replenish(c);
+ }
+}
+
+static void
+ethtx(Ether *edev)
+{
+ Ctlr *c;
+ ulong *r;
+ Block *bp;
+
+ c = edev->ctlr;
+ ilock(&c->txlock);
+ for(;;){
+ r = &c->txr[2 * c->txi];
+ if((r[1] & TxUsed) == 0){
+ print("eth: transmit buffer full\n");
+ break;
+ }
+ bp = qget(edev->oq);
+ if(bp == nil)
+ break;
+ if(c->txs[c->txi] != nil)
+ freeb(c->txs[c->txi]);
+ c->txs[c->txi] = bp;
+ cleandse(bp->rp, bp->wp);
+ clean2pa(PADDR(bp->rp), PADDR(bp->wp));
+ r[0] = PADDR(bp->rp);
+ r[1] = BLEN(bp) | FrameEnd | TxUsed;
+ if(r == c->txr + 2 * (TXRING - 1))
+ r[1] |= 1<<30;
+ coherence();
+ r[1] &= ~TxUsed;
+ coherence();
+ c->r[NET_CTRL] |= STARTTX;
+ c->txi = (c->txi + 1) & (TXRING - 1);
+ }
+ iunlock(&c->txlock);
+}
+
+static void
+ethirq(Ureg *, void *arg)
+{
+ Ether *edev;
+ Ctlr *c;
+ ulong fl;
+
+ edev = arg;
+ c = edev->ctlr;
+ fl = c->r[INTR_STATUS];
+ c->r[INTR_STATUS] = fl;
+ if((fl & MGMTDONE) != 0)
+ wakeup(&c->phy);
+ if((fl & TXUNDER) != 0)
+ ethtx(edev);
+ if((fl & RXCOMPL) != 0)
+ ethrx(edev);
+ if((fl & RXUSED) != 0)
+ print("eth: DMA read RX descriptor with used bit set, shouldn't happen\n");
+ if((fl & RXOVER) != 0)
+ print("eth: RX overrun, shouldn't happen\n");
+}
+
+static int
+ethinit(Ether *edev)
+{
+ Ctlr *c;
+ int i;
+ uintptr rxrpa, txrpa;
+
+ c = edev->ctlr;
+ c->r[NET_CTRL] = 0;
+ c->r[RX_STATUS] = 0xf;
+ c->r[TX_STATUS] = 0xff;
+ c->r[INTR_DIS] = 0x7FFFEFF;
+ c->r[NET_CFG] = MDC_DIV << 18 | FDEN | SPEED | RX1536EN | GIGE_EN | RXCHKSUMEN;
+ c->r[SPEC_ADDR1_BOT] = edev->ea[0] | edev->ea[1] << 8 | edev->ea[2] << 16 | edev->ea[3] << 24;
+ c->r[SPEC_ADDR1_TOP] = edev->ea[4] | edev->ea[5] << 8;
+ c->r[DMA_CFG] = TXCHKSUMEN | (Rbsz/64) << 16 | 1 << 10 | 3 << 8 | 0x10;
+
+ rxrpa = ualloc(8 * RXRING, &c->rxr);
+ txrpa = ualloc(8 * TXRING, &c->txr);
+ c->rxs = xspanalloc(4 * RXRING, 4, 0);
+ c->txs = xspanalloc(4 * TXRING, 4, 0);
+ for(i = 0; i < 2 * RXRING; ){
+ c->rxr[i++] = 1;
+ c->rxr[i++] = 0;
+ }
+ c->rxconsi = 1;
+ replenish(c);
+ c->rxconsi = 0;
+ replenish(c);
+ for(i = 0; i < 2 * TXRING; ){
+ c->txr[i++] = 0;
+ c->txr[i++] = 1<<31;
+ }
+ c->txr[2 * (TXRING - 1)] |= 1<<30;
+ c->r[RX_QBAR] = rxrpa;
+ c->r[TX_QBAR] = txrpa;
+
+ c->r[NET_CTRL] = MDEN | TXEN | RXEN;
+ c->r[INTR_EN] = MGMTDONE | TXUNDER | RXCOMPL | RXUSED | RXOVER;
+ return 0;
+}
+
+static void
+ethattach(Ether *edev)
+{
+ Ctlr *c;
+
+ c = edev->ctlr;
+ if(c->attach)
+ return;
+ c->attach = 1;
+ kproc("ethproc", ethproc, edev);
+}
+
+static int
+etherpnp(Ether *edev)
+{
+ static Ctlr ct;
+ static uchar mac[] = {0x0e, 0xa7, 0xde, 0xad, 0xbe, 0xef};
+
+ if(ct.r != nil)
+ return -1;
+
+ memmove(edev->ea, mac, 6);
+ edev->ctlr = &ct;
+ edev->port = ETH0_BASE;
+ ct.r = vmap(edev->port, BY2PG);
+ edev->irq = ETH0IRQ;
+ edev->irqlevel = LEVEL;
+ edev->ctlr = &ct;
+ edev->interrupt = ethirq;
+ edev->transmit = ethtx;
+ edev->attach = ethattach;
+ edev->arg = edev;
+ edev->mbps = 1000;
+
+ if(ethinit(edev) < 0){
+ edev->ctlr = nil;
+ return -1;
+ }
+ return 0;
+}
+
+void
+etherzynqlink(void)
+{
+ addethercard("eth", etherpnp);
+}
--- /dev/null
+++ b/sys/src/9/zynq/fns.h
@@ -1,0 +1,75 @@
+#include "../port/portfns.h"
+
+int tas(void *);
+int cmpswap(long *, long, long);
+void evenaddr(uintptr);
+void* kaddr(uintptr);
+uintptr paddr(void *);
+uintptr cankaddr(uintptr);
+void procsave(Proc *);
+void procrestore(Proc *);
+void idlehands(void);
+void coherence(void);
+void procfork(Proc *);
+void procsetup(Proc *);
+KMap* kmap(Page *);
+void kunmap(KMap *);
+
+#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
+#define getpgcolor(a) 0
+#define kmapinval()
+#define KADDR(a) kaddr(a)
+#define PADDR(a) paddr((void*)(a))
+#define userureg(ur) (((ur)->psr & PsrMask) == PsrMusr)
+#define VA(k) ((void*)(k))
+#define PTR2UINT(p) ((uintptr)(p))
+
+void uartinit(void);
+void mmuinit(void);
+uintptr ttbget(void);
+void ttbput(uintptr);
+void cycles(uvlong *);
+void kexit(Ureg *);
+ulong getifsr(void);
+ulong getdfsr(void);
+uintptr getifar(void);
+uintptr getdfar(void);
+void links(void);
+void* vmap(uintptr, ulong);
+void timerinit(void);
+void setpmcr(ulong);
+void* tmpmap(uintptr);
+void tmpunmap(void*);
+void flushpg(void *);
+void setasid(ulong);
+void flushtlb(void);
+void touser(void *);
+void noted(Ureg *, ulong);
+void l1switch(L1 *, int);
+void intrenable(int, void (*)(Ureg *, void *), void *, int, char *);
+void intrinit(void);
+void intr(Ureg *);
+int uartconsole(void);
+void fpoff(void);
+void fpsave(FPsave *);
+void fprestore(FPsave *);
+void fpinit(void);
+void fpclear(void);
+char* getconf(char *);
+void invalise(void *, void *);
+void cleandse(void *, void *);
+void invaldse(void *, void *);
+void clinvdse(void *, void *);
+void invaldln(void *);
+void cleandln(void *);
+void clinvdln(void *);
+uintptr ualloc(ulong, void **);
+void clean2pa(uintptr, uintptr);
+void inval2pa(uintptr, uintptr);
+void archinit(void);
+uintptr palookur(void *);
+void screeninit(void);
+int isaconfig(char*, int, ISAConf*);
+void *ucalloc(usize);
+void *ucallocalign(usize, int, int);
+void ucfree(void *);
--- /dev/null
+++ b/sys/src/9/zynq/init9.s
@@ -1,0 +1,7 @@
+TEXT _main(SB), $-4
+ MOVW $setR12(SB), R12
+ MOVW 4(R13), R0
+ ADD $4, R13, R1
+ SUB $4, R13
+ MOVW R1, 8(R13)
+ MOVW $startboot(SB), R15
--- /dev/null
+++ b/sys/src/9/zynq/intr.c
@@ -1,0 +1,118 @@
+#include "u.h"
+#include <ureg.h>
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+enum {
+ NINTR = 96,
+ NPRIVATE = 32
+};
+
+static struct irq {
+ void (*f)(Ureg *, void *);
+ void *arg;
+ char *name;
+} irqs[NINTR];
+
+enum {
+ ICCICR = 0x100/4,
+ ICCPMR,
+ ICCBPR,
+ ICCIAR,
+ ICCEOIR,
+ ICDDCR = 0x1000/4,
+ ICDISR = 0x1080/4,
+ ICDISER = 0x1100/4,
+ ICDICER = 0x1180/4,
+ ICDICPR = 0x1280/4,
+ ICDABR = 0x1300/4,
+ ICDIPRI = 0x1400/4,
+ ICDIPTR = 0x1800/4,
+ ICDICFR = 0x1C00/4,
+};
+
+void
+intrinit(void)
+{
+ int i;
+
+ mpcore[ICDDCR] = 3;
+ mpcore[ICCICR] = 7;
+ mpcore[ICCBPR] = 3;
+ mpcore[ICCPMR] = 255;
+
+ /* disable all irqs and clear any pending interrupts */
+ for(i = 0; i < NINTR/32; i++){
+ mpcore[ICDISR + i] = -1;
+ mpcore[ICDICER + i] = -1;
+ mpcore[ICDICPR + i] = -1;
+ mpcore[ICDABR + i] = 0;
+ }
+}
+
+void
+intrenable(int irq, void (*f)(Ureg *, void *), void *arg, int type, char *name)
+{
+ ulong *e, s;
+ struct irq *i;
+
+ if(f == nil)
+ panic("intrenable: f == nil");
+ if(irq < 0 || irq >= NINTR)
+ panic("intrenable: invalid irq %d", irq);
+ if(type != LEVEL && type != EDGE)
+ panic("intrenable: invalid type %d", type);
+ if(irqs[irq].f != nil)
+ panic("intrenable: handler already assigned");
+ if(irq >= NPRIVATE){
+ e = &mpcore[ICDIPTR + (irq >> 2)];
+ s = irq << 3 & 24;
+ *e = *e & ~(3 << s) | 1 << s;
+ e = &mpcore[ICDICFR + (irq >> 4)];
+ s = irq << 1 & 30 | 1;
+ *e = *e & ~(1 << s) | type << s;
+ }
+ ((uchar*)&mpcore[ICDIPRI])[irq] = 0;
+ i = &irqs[irq];
+ i->f = f;
+ i->arg = arg;
+ i->name = name;
+ mpcore[ICDISER + (irq >> 5)] = 1 << (irq & 31);
+ mpcore[ICDABR + (irq >> 5)] |= 1 << (irq & 31);
+}
+
+void
+intr(Ureg *ureg)
+{
+ ulong v;
+ int irq;
+ struct irq *i;
+
+ v = mpcore[ICCIAR];
+ irq = v & 0x3ff;
+ if(irq == 0x3ff)
+ return;
+
+ m->intr++;
+ m->lastintr = irq;
+ i = &irqs[irq];
+ if(i->f == nil)
+ print("irq without handler %d\n", irq);
+ else
+ i->f(ureg, i->arg);
+ mpcore[ICCEOIR] = v;
+
+ if(up != nil){
+ if(irq == TIMERIRQ){
+ if(up->delaysched){
+ splhi();
+ sched();
+ }
+ }else
+ preempted();
+ }
+}
--- /dev/null
+++ b/sys/src/9/zynq/io.h
@@ -1,0 +1,25 @@
+#define PS_CLK 33
+
+#define UART_BASE 0xE0001000
+#define USB0_BASE 0xE0002000
+#define USB1_BASE 0xE0003000
+#define ETH0_BASE 0xE000B000
+#define QSPI_BASE 0xE000D000
+#define SLCR_BASE 0xF8000000
+#define DEVC_BASE 0xF8007000
+#define MPCORE_BASE 0xF8F00000
+#define L2_BASE 0xF8F02000
+#define OCM_BASE 0xFFFC0000
+
+#define TIMERIRQ 29
+#define XADCIRQ 39
+#define DEVCIRQ 40
+#define USB0IRQ 53
+#define ETH0IRQ 54
+#define USB1IRQ 76
+#define UART1IRQ 82
+
+#define LEVEL 0
+#define EDGE 1
+
+#define XADCINTERVAL 500
--- /dev/null
+++ b/sys/src/9/zynq/l.s
@@ -1,0 +1,460 @@
+#include "mem.h"
+#include "io.h"
+
+#define PUTC(c) MOVW $(c), R0; MOVW R0, (R8)
+
+TEXT _start(SB), $-4
+ MOVW $(KTZERO-KZERO), R13
+ MOVW $0xE0001030, R8
+
+ PUTC('P')
+ MOVW $0, R0
+ MOVW R0, R1
+ MOVW $(CONFADDR-KZERO), R2
+_start0:
+ MOVW.P R0, 4(R1)
+ CMP.S R1, R2
+ BNE _start0
+
+ PUTC('l')
+ MOVW $SECSZ, R0
+ MOVW $(CPU0L1-KZERO), R4
+ MOVW $KZERO, R1
+ ADD R1>>(SECSH-2), R4, R1
+ MOVW $(L1SEC|L1CACHED|L1KERRW), R2
+ MOVW $(-KZERO), R3
+_start1:
+ MOVW.P R2, 4(R1)
+ ADD R0, R2
+ CMP.S R2, R3
+ BGE _start1
+
+ PUTC('a')
+ MOVW $L2SZ, R0
+ MOVW $VMAP, R1
+ ADD R1>>(SECSH-2), R4, R1
+ MOVW $((VMAPL2-KZERO)|L1PT), R2
+ MOVW $(VMAPL2-KZERO+VMAPL2SZ), R3
+_start2:
+ MOVW.P R2, 4(R1)
+ ADD R0, R2
+ CMP.S R2, R3
+ BGE _start2
+
+ MOVW $(UART_BASE|L2VALID|L2DEVICE|L2KERRW), R0
+ MOVW $(VMAPL2 - KZERO), R1
+ MOVW R0, (R1)
+
+ PUTC('n')
+ MOVW $0, R0
+ MCR 15, 0, R0, C(8), C(7), 0
+ MOVW $(CPU0L1 - KZERO | TTBATTR), R1
+ MCR 15, 0, R1, C(2), C(0), 0
+ MOVW $0x20c5047b, R1
+ MOVW $_virt(SB), R2
+ PUTC(' ')
+ MCR 15, 0, R1, C(1), C(0), 0
+ MOVW R2, R15
+
+TEXT _virt(SB), $-4
+ DSB
+ ISB
+
+ MOVW $(MACH(0) + MACHSIZE), R13
+ MOVW $(MACH(0) + 12), R0
+ BL loadsp(SB)
+ MOVW $vectors(SB), R1
+ MCR 15, 0, R1, C(12), C(0)
+
+ /* enable MMU permission checking */
+ MOVW $0x55555555, R0
+ MCR 15, 0, R0, C(3), C(0), 0
+
+ /* enable maths coprocessors in CPACR but disable them in FPEXC */
+ MRC 15, 0, R0, C(1), C(0), 2
+ ORR $(15<<20), R0
+ MCR 15, 0, R0, C(1), C(0), 2
+
+ VMRS(0xe, FPEXC, 0)
+ BIC $(3<<30), R0
+ VMSR(0xe, 0, FPEXC)
+
+ /* enable L1 cache */
+ MOVW $0, R0
+ MCR 15, 0, R0, C(7), C(5), 0
+ MCR 15, 0, R0, C(7), C(5), 6
+ BL l1dclear(SB)
+ MRC 15, 0, R0, C(1), C(0), 1
+ ORR $(1|1<<6), R0
+ MCR 15, 0, R0, C(1), C(0), 1
+ MRC 15, 0, R0, C(1), C(0), 0
+ ORR $(1<<12|1<<2), R0
+ MCR 15, 0, R0, C(1), C(0), 0
+ DSB
+ ISB
+
+ MOVW $(VMAP+0x30), R8
+ PUTC('9')
+
+ MOVW $setR12(SB), R12
+ MOVW $MACH(0), R(Rmach)
+ MOVW $0, R(Rup)
+ BL main(SB)
+ B idlehands(SB)
+
+ BL _div(SB) /* hack to load _div */
+
+TEXT touser(SB), $-4
+ CPS(CPSID)
+
+ SUB $12, R13
+ MOVW R0, (R13)
+ MOVW $0, R1
+ MOVW R1, 4(R13)
+ MOVW $(UTZERO+0x20), R1
+ MOVW R1, 8(R13)
+
+ MOVW CPSR, R1
+ BIC $(PsrMask|PsrDirq|PsrDfiq), R1
+ ORR $PsrMusr, R1
+ MOVW R1, SPSR
+
+ MOVW $(KTZERO-(15*4)), R0
+ MOVM.IA (R0), [R0-R12]
+
+ MOVM.IA.S (R13), [R13-R14]
+ ADD $8, R13
+ MOVM.IA.W.S (R13), [R15]
+
+TEXT forkret(SB), $-4
+ MOVW (16*4)(R13), R0
+ MOVW R0, SPSR
+ MOVM.IA.W (R13), [R0-R12]
+ MOVM.IA.S (R13), [R13-R14]
+ ADD $16, R13
+ DSB
+ ISB
+ MOVM.IA.W.S (R13), [R15]
+
+TEXT nope(SB), $-4 // NOPE
+ MOVW $(VMAP+0x30), R8
+ PUTC(13)
+ PUTC(10)
+ MOVW R14, R7
+ BL puthex(SB)
+ PUTC(' ')
+ PUTC('N')
+ PUTC('O')
+ PUTC('P')
+ PUTC('E')
+_nope: B _nope
+
+TEXT loadsp(SB), $0
+ CPS(CPSMODE | PsrMabt)
+ MOVW R0, R13
+ CPS(CPSMODE | PsrMund)
+ MOVW R0, R13
+ CPS(CPSMODE | PsrMirq)
+ MOVW R0, R13
+ CPS(CPSMODE | PsrMfiq)
+ MOVW R0, R13
+ CPS(CPSMODE | PsrMsvc)
+ RET
+
+TEXT cputhex(SB), $0
+ MOVW R0, R7
+ MOVW $(VMAP+0x30), R8
+TEXT puthex(SB), $0
+_p0:
+ MOVW -4(R8), R6
+ AND.S $(1<<3), R6
+ BEQ _p0
+#define DIG MOVW R7>>28, R6; AND $15, R6; ADD $'0', R6; CMP $'9', R6; ADD.GT $7, R6; MOVW R6, (R8); MOVW R7<<4, R7
+ DIG; DIG; DIG; DIG
+ DIG; DIG; DIG; DIG
+ MOVW $13, R6
+ MOVW R6, (R8)
+ MOVW $10, R6
+ MOVW R6, (R8)
+ RET
+
+TEXT spllo(SB), $-4
+ MOVW CPSR, R0
+ CPS(CPSIE)
+ RET
+
+TEXT splhi(SB), $-4
+ MOVW R14, 4(R(Rmach))
+ MOVW CPSR, R0
+ CPS(CPSID)
+ RET
+
+TEXT splx(SB), $-4
+ MOVW R14, 4(R(Rmach))
+ MOVW R0, R1
+ MOVW CPSR, R0
+ MOVW R1, CPSR
+ RET
+
+TEXT spldone(SB), $-4
+ RET
+
+TEXT islo(SB), $0
+ MOVW CPSR, R0
+ AND $(PsrDirq), R0
+ EOR $(PsrDirq), R0
+ RET
+
+TEXT setlabel(SB), $-4
+ MOVW R13, 0(R0)
+ MOVW R14, 4(R0)
+ MOVW $0, R0
+ RET
+
+TEXT gotolabel(SB), $-4
+ MOVW 0(R0), R13
+ MOVW 4(R0), R14
+ MOVW $1, R0
+ RET
+
+TEXT tas(SB), $0
+ DMB
+ MOVW $0xDEADDEAD, R2
+_tas1:
+ LDREX (R0), R1
+ STREX R2, (R0), R3
+ CMP.S $0, R3
+ BNE _tas1
+ MOVW R1, R0
+ DMB
+ RET
+
+TEXT coherence(SB), $0
+ DSB
+ RET
+
+TEXT idlehands(SB), $0
+ DSB
+ WFE
+ RET
+
+TEXT ttbget(SB), $0
+ MRC 15, 0, R0, C(2), C(0), 0
+ BIC $0x7f, R0
+ RET
+
+TEXT ttbput(SB), $0
+ ORR $(TTBATTR), R0
+ MCR 15, 0, R0, C(2), C(0), 0
+ RET
+
+TEXT flushpg(SB), $0
+ MCR 15, 0, R0, C(8), C(7), 3
+ DSB
+ RET
+
+TEXT flushtlb(SB), $0
+ MCR 15, 0, R0, C(8), C(3), 0
+ DSB
+ RET
+
+TEXT setasid(SB), $0
+ MCR 15, 0, R0, C(13), C(0), 1
+ RET
+
+TEXT getifar(SB), $0
+ MRC 15, 0, R0, C(6), C(0), 2
+ RET
+
+TEXT getdfar(SB), $0
+ MRC 15, 0, R0, C(6), C(0), 0
+ RET
+
+TEXT getifsr(SB), $0
+ MRC 15, 0, R0, C(5), C(0), 1
+ RET
+
+TEXT getdfsr(SB), $0
+ MRC 15, 0, R0, C(5), C(0), 0
+ RET
+
+TEXT setpmcr(SB), $0
+ MCR 15, 0, R0, C(9), C(12), 0
+ RET
+
+TEXT perfticks(SB), $0
+ MRC 15, 0, R0, C(9), C(13), 0
+ RET
+
+TEXT cycles(SB), $0
+ MRC 15, 0, R1, C(9), C(13), 0
+ MOVW R1, (R0)
+ MOVW 24(R(Rmach)), R1
+ MRC 15, 0, R2, C(9), C(12), 3
+ AND.S $(1<<31), R2
+ BEQ _cycles0
+ MCR 15, 0, R2, C(9), C(12), 3
+ ADD $1, R1
+ MOVW R1, 24(R(Rmach))
+_cycles0:
+ MOVW R1, 4(R0)
+ RET
+
+TEXT fpinit(SB), $0
+ MOVW $(1<<30), R0
+ VMSR(0xe, 0, FPEXC)
+ MOVW $0, R0
+ VMSR(0xe, 0, FPSCR)
+ RET
+
+TEXT fpsave(SB), $0
+ VMRS(0xe, FPEXC, 1)
+ VMRS(0xe, FPSCR, 2)
+ MOVM.IA.W [R1-R2], (R0)
+ WORD $0xeca00b20
+ WORD $0xece00b20
+ RET
+
+TEXT fprestore(SB), $0
+ MOVM.IA.W (R0), [R1-R2]
+ VMSR(0xe, 1, FPEXC)
+ VMSR(0xe, 2, FPSCR)
+ WORD $0xecb00b20
+ WORD $0xecf00b20
+ RET
+
+TEXT fpoff(SB), $0
+ MOVW $0, R1
+ VMSR(0xe, 1, FPEXC)
+ RET
+
+TEXT fpclear(SB), $0
+ VMRS(0xe, FPEXC, 1)
+ AND $(3<<30), R1
+ VMSR(0xe, 1, FPEXC)
+ RET
+
+#define Rnoway R1
+#define Rwayinc R2
+#define Rmaxway R3
+#define Rsetinc R4
+#define Rmaxset R5
+
+TEXT l1dclear(SB), $0
+ MOVW $0, R0
+ MCR 15, 2, R0, C(0), C(0), 0
+ MRC 15, 1, R9, C(0), C(0), 0
+ AND $7, R9, R8
+ ADD $4, R8
+ MOVW $1, Rsetinc
+ MOVW Rsetinc<<R8, Rsetinc
+
+ MOVW R9>>13, Rmaxset
+ AND $0x7fff, Rmaxset
+ MOVW Rmaxset<<R8, Rmaxset
+
+ MOVW R9>>3, R0
+ AND $0x3ff, R0
+ MOVW $(1<<31), Rwayinc
+ MOVW $(1<<31), Rnoway
+ MOVW R0, Rmaxway
+ ADD $1, R0
+_l1dclear0:
+ MOVW.S R0>>1, R0
+ BEQ _l1dclear1
+ MOVW Rwayinc>>1, Rwayinc
+ MOVW Rnoway->1, Rnoway
+ MOVW Rmaxway@>1, Rmaxway
+ B _l1dclear0
+_l1dclear1:
+ MOVW Rwayinc<<1, Rwayinc
+ MVN Rnoway<<1, Rnoway
+ BIC Rnoway, Rmaxway
+
+ MOVW $0, R0
+_l1dclear2:
+ MCR 15, 0, R0, C(7), C(14), 2
+ ADD Rwayinc, R0
+ CMP.S Rmaxway, R0
+ BLT _l1dclear2
+ AND Rnoway, R0
+ ADD Rsetinc, R0
+ CMP.S Rmaxset, R0
+ BLT _l1dclear2
+ RET
+
+TEXT invalise(SB), $0
+ MOVW 4(FP), R1
+ ADD $(LINSIZ - 1), R1
+ BIC $(LINSIZ - 1), R0
+ BIC $(LINSIZ - 1), R1
+_invalise0:
+ MCR 15, 0, R0, C(7), C(5), 1
+ ADD $LINSIZ, R0
+ CMP.S R1, R0
+ BLT _invalise0
+ RET
+
+TEXT cleandse(SB), $0
+ DSB
+ MOVW 4(FP), R1
+ ADD $(LINSIZ - 1), R1
+ BIC $(LINSIZ - 1), R0
+ BIC $(LINSIZ - 1), R1
+_cleandse0:
+ MCR 15, 0, R0, C(7), C(10), 1
+ ADD $LINSIZ, R0
+ CMP.S R1, R0
+ BLT _cleandse0
+ DSB
+ RET
+
+TEXT invaldse(SB), $0
+ MOVW 4(FP), R1
+ ADD $(LINSIZ - 1), R1
+ BIC $(LINSIZ - 1), R0
+ BIC $(LINSIZ - 1), R1
+_invaldse0:
+ MCR 15, 0, R0, C(7), C(6), 1
+ ADD $LINSIZ, R0
+ CMP.S R1, R0
+ BLT _invaldse0
+ DSB
+ RET
+
+TEXT clinvdse(SB), $0
+ DSB
+ MOVW 4(FP), R1
+ ADD $(LINSIZ - 1), R1
+ BIC $(LINSIZ - 1), R0
+ BIC $(LINSIZ - 1), R1
+_clinvdse0:
+ MCR 15, 0, R0, C(7), C(14), 1
+ ADD $LINSIZ, R0
+ CMP.S R1, R0
+ BLT _clinvdse0
+ DSB
+ RET
+
+TEXT cleandln(SB), $0
+ DSB
+ MCR 15, 0, R0, C(7), C(10), 1
+ DSB
+ RET
+
+TEXT invaldln(SB), $0
+ MCR 15, 0, R0, C(7), C(6), 1
+ DSB
+ RET
+
+TEXT clinvdln(SB), $0
+ DSB
+ MCR 15, 0, R0, C(7), C(14), 1
+ DSB
+ RET
+
+TEXT palookur(SB), $0
+ MCR 15, 0, R0, C(7), C(8), 2
+ DSB
+ MRC 15, 0, R0, C(7), C(4), 0
+ RET
--- /dev/null
+++ b/sys/src/9/zynq/ltrap.s
@@ -1,0 +1,98 @@
+#include "mem.h"
+#include "io.h"
+
+TEXT vectors(SB), $-4
+ MOVW $_start-KZERO(SB), R15
+ MOVW $_vexc(SB), R15
+ MOVW $_vsvc(SB), R15
+ MOVW $_viabt(SB), R15
+ MOVW $_vexc(SB), R15
+ MOVW $vectors(SB), R15
+ MOVW $_vexc(SB), R15
+ MOVW $_vexc(SB), R15
+
+TEXT _viabt(SB), $-4
+ CPS(CPSID)
+ CLREX
+ DSB
+ MOVW R14, 8(R13)
+ MOVW SPSR, R14
+ MOVW R14, 4(R13)
+ MOVW CPSR, R14
+ AND $0x1e, R14
+ B _exc
+
+
+TEXT _vexc(SB), $-4
+ CPS(CPSID)
+ CLREX
+ DSB
+ MOVW R14, 8(R13)
+ MOVW SPSR, R14
+ MOVW R14, 4(R13)
+ MOVW CPSR, R14
+ AND $0x1f, R14
+_exc:
+ MOVW R14, 0(R13)
+ CPS(CPSMODE | PsrMsvc)
+
+ SUB $(18*4), R13
+ MOVM.IA [R0-R14], (R13)
+
+ MOVW $MACH(0), R(Rmach) /* FIXME */
+ MOVW 8(R(Rmach)), R(Rup)
+ MOVW $setR12(SB), R12
+
+ ADD $12, R(Rmach), R0
+ MOVM.IA (R0), [R1-R3]
+ ADD $(15*4), R13, R0
+ MOVM.IA [R1-R3], (R0)
+
+ AND.S $0xf, R2
+ ADD.NE $(18*4), R13, R0
+ MOVW.NE R0, (13*4)(R13)
+ ADD.EQ $(13*4), R13, R0
+ MOVM.IA.S.EQ [R13-R14], (R0)
+
+ MOVW R13, R0
+ SUB $8, R13
+ BL trap(SB)
+ ADD $8, R13
+
+ MOVW (16*4)(R13), R0
+ MOVW R0, SPSR
+ AND.S $0xf, R0
+ BEQ _uret
+ MOVW R(Rmach), (Rmach*4)(R13)
+ MOVM.IA (R13), [R0-R14]
+ DSB
+ MOVM.DB.S (R13), [R15]
+
+TEXT _vsvc(SB), $-4
+ CLREX
+ DSB
+ MOVW.W R14, -4(R13)
+ MOVW SPSR, R14
+ MOVW.W R14, -4(R13)
+ MOVW $PsrMsvc, R14
+ MOVW.W R14, -4(R13)
+ MOVM.DB.S [R0-R14], (R13)
+ SUB $(15*4), R13
+
+ MOVW $MACH(0), R(Rmach) /* FIXME */
+ MOVW 8(R(Rmach)), R(Rup)
+ MOVW $setR12(SB), R12
+
+ MOVW R13, R0
+ SUB $8, R13
+ BL syscall(SB)
+ ADD $8, R13
+
+ MOVW (16*4)(R13), R0
+ MOVW R0, SPSR
+_uret:
+ MOVM.IA.S (R13), [R0-R14]
+ ADD $(17*4), R13
+ DSB
+ ISB
+ MOVM.IA.S.W (R13), [R15]
--- /dev/null
+++ b/sys/src/9/zynq/main.c
@@ -1,0 +1,372 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "init.h"
+#include "pool.h"
+#include "io.h"
+#include "../port/error.h"
+#include "tos.h"
+
+Conf conf;
+int normalprint, delaylink;
+uchar *sp;
+
+enum { MAXCONF = 64 };
+
+char *confname[MAXCONF], *confval[MAXCONF];
+int nconf;
+
+void
+exit(int)
+{
+ NOPE
+}
+
+void
+reboot(void *, void *, ulong)
+{
+ NOPE
+}
+
+void
+evenaddr(uintptr va)
+{
+ if((va & 3) != 0){
+ dumpstack();
+ postnote(up, 1, "sys: odd address", NDebug);
+ error(Ebadarg);
+ }
+}
+
+void
+procfork(Proc *p)
+{
+ ulong s;
+
+ p->kentry = up->kentry;
+ p->pcycles = -p->kentry;
+
+ s = splhi();
+ switch(up->fpstate & ~FPillegal){
+ case FPactive:
+ fpsave(&up->fpsave);
+ up->fpstate = FPinactive;
+ case FPinactive:
+ p->fpsave = up->fpsave;
+ p->fpstate = FPinactive;
+ }
+ splx(s);
+}
+
+void
+procsetup(Proc *p)
+{
+ p->fpstate = FPinit;
+ fpoff();
+
+ cycles(&p->kentry);
+ p->pcycles = -p->kentry;
+}
+
+int
+cmpswap(long *a, long b, long c)
+{
+ extern int cas(int *, int, int);
+
+ return cas((int *) a, b, c);
+}
+
+void
+kexit(Ureg *)
+{
+ Tos *tos;
+ uvlong t;
+
+ tos = (Tos*)(USTKTOP-sizeof(Tos));
+ cycles(&t);
+ tos->kcycles += t - up->kentry;
+ tos->pcycles = t + up->pcycles;
+ tos->pid = up->pid;
+}
+
+ulong *l2;
+
+void
+l2init(void)
+{
+ enum {
+ CTRL = 0x100/4,
+ AUX,
+ TAGRAM,
+ DATARAM,
+ INVPA = 0x770/4,
+ INVWAY = 0x77C/4,
+ PREFETCH = 0xF60/4,
+ };
+
+ mpcore[0] |= 1;
+ slcr[0xa1c/4] = 0x020202;
+ l2 = vmap(L2_BASE, BY2PG);
+ l2[CTRL] &= ~1;
+ l2[TAGRAM] = l2[TAGRAM] & ~0x777 | 0x111;
+ l2[DATARAM] = l2[DATARAM] & ~0x777 | 0x121;
+ l2[PREFETCH] |= 3<<28;
+ l2[AUX] |= 3<<28 | 1<<20;
+ l2[INVWAY] = 0xff;
+ while((l2[INVPA] & 1) != 0)
+ ;
+ l2[CTRL] = 1;
+}
+
+void
+clean2pa(uintptr start, uintptr end)
+{
+ uintptr pa;
+
+ start &= ~31;
+ end = (end + 31) & ~31;
+ for(pa = start; pa < end; pa += 32)
+ l2[0x7b0/4] = pa;
+}
+
+void
+inval2pa(uintptr start, uintptr end)
+{
+ uintptr pa;
+
+ start &= ~31;
+ end = (end + 31) & ~31;
+ for(pa = start; pa < end; pa += 32)
+ l2[0x770/4] = pa;
+}
+
+static void
+options(void)
+{
+ long i, n;
+ char *cp, *line[MAXCONF], *p, *q;
+
+ cp = (char *) CONFADDR;
+
+ p = cp;
+ for(q = cp; *q; q++){
+ if(*q == '\r')
+ continue;
+ if(*q == '\t')
+ *q = ' ';
+ *p++ = *q;
+ }
+ *p = 0;
+
+ n = getfields(cp, line, MAXCONF, 1, "\n");
+ for(i = 0; i < n; i++){
+ if(*line[i] == '#')
+ continue;
+ cp = strchr(line[i], '=');
+ if(cp == nil)
+ continue;
+ *cp++ = '\0';
+ confname[nconf] = line[i];
+ confval[nconf] = cp;
+ nconf++;
+ }
+
+}
+
+void
+confinit(void)
+{
+ int i;
+
+ conf.nmach = 1;
+ conf.nproc = 100;
+ conf.ialloc = 16*1024*1024;
+ conf.nimage = conf.nproc;
+ conf.mem[0].base = PGROUND((ulong)end - KZERO);
+ conf.mem[0].limit = 1024*1024*1024;
+ conf.npage = 0;
+ for(i = 0; i < nelem(conf.mem); i++)
+ conf.npage += conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base) >> PGSHIFT;
+ conf.upages = conf.npage - 100*1024*1024 / BY2PG;
+}
+
+static uchar *
+pusharg(char *p)
+{
+ int n;
+
+ n = strlen(p) + 1;
+ sp -= n;
+ memmove(sp, p, n);
+ return sp;
+}
+
+static void
+bootargs(void *base)
+{
+ int i, ac;
+ uchar *av[32];
+ uchar **lsp;
+
+ sp = (uchar *) base + BY2PG - sizeof(Tos);
+
+ ac = 0;
+ av[ac++] = pusharg("boot");
+ sp = (uchar *) ((ulong) sp & ~3);
+ sp -= (ac + 1) * sizeof(sp);
+ lsp = (uchar **) sp;
+ for(i = 0; i < ac; i++)
+ lsp[i] = av[i] + ((USTKTOP - BY2PG) - (ulong) base);
+ lsp[i] = 0;
+ sp += (USTKTOP - BY2PG) - (ulong) base;
+ sp -= BY2WD;
+}
+
+static void
+init0(void)
+{
+ char buf[ERRMAX];
+ int i;
+
+ up->nerrlab = 0;
+ spllo();
+
+ up->slash = namec("#/", Atodir, 0, 0);
+ pathclose(up->slash->path);
+ up->slash->path = newpath("/");
+ up->dot = cclone(up->slash);
+
+ chandevinit();
+ uartconsole();
+
+ if(!waserror()){
+ ksetenv("cputype", "arm", 0);
+ if(cpuserver)
+ ksetenv("service", "cpu", 0);
+ else
+ ksetenv("service", "terminal", 0);
+ ksetenv("console", "0", 0);
+ snprint(buf, sizeof(buf), "zynq %s", conffile);
+ ksetenv("terminal", buf, 0);
+ for(i = 0; i < nconf; i++){
+ if(*confname[i] != '*')
+ ksetenv(confname[i], confval[i], 0);
+ ksetenv(confname[i], confval[i], 1);
+ }
+ poperror();
+ }
+ kproc("alarm", alarmkproc, 0);
+ touser(sp);
+}
+
+void
+userinit(void)
+{
+ Proc *p;
+ Segment *s;
+ void *v;
+ Page *pg;
+
+ p = newproc();
+ p->pgrp = newpgrp();
+ p->egrp = smalloc(sizeof(Egrp));
+ p->egrp->ref = 1;
+ p->fgrp = dupfgrp(nil);
+ p->rgrp = newrgrp();
+ p->procmode = 0640;
+
+ kstrdup(&eve, "");
+ kstrdup(&p->text, "*init*");
+ kstrdup(&p->user, eve);
+
+ procsetup(p);
+
+ p->sched.pc = (ulong)init0;
+ p->sched.sp = (ulong)p->kstack + KSTACK - (sizeof(Sargs) + BY2WD);
+
+ s = newseg(SG_STACK, USTKTOP - USTKSIZE, USTKSIZE / BY2PG);
+ p->seg[SSEG] = s;
+ pg = newpage(0, 0, USTKTOP - BY2PG);
+ v = tmpmap(pg->pa);
+ memset(v, 0, BY2PG);
+ segpage(s, pg);
+ bootargs(v);
+ tmpunmap(v);
+
+ s = newseg(SG_TEXT, UTZERO, 1);
+ s->flushme++;
+ p->seg[TSEG] = s;
+ pg = newpage(0, 0, UTZERO);
+ memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
+
+ segpage(s, pg);
+ v = tmpmap(pg->pa);
+ memset(v, 0, BY2PG);
+ memmove(v, initcode, sizeof(initcode));
+ tmpunmap(v);
+
+ ready(p);
+}
+
+void
+sanity(void)
+{
+ static int dat = 0xdeadbeef;
+ extern ulong vectors[];
+
+ assert(dat == 0xdeadbeef);
+ assert(((uintptr)vectors & 31) == 0);
+ assert(sizeof(Mach) + KSTACK <= MACHSIZE);
+ assert((KZERO & SECSZ - 1) == 0);
+}
+
+char *
+getconf(char *n)
+{
+ int i;
+
+ for(i = 0; i < nconf; i++)
+ if(cistrcmp(confname[i], n) == 0)
+ return confval[i];
+ return nil;
+}
+
+int
+isaconfig(char *, int, ISAConf*)
+{
+ return 1;
+}
+
+void
+main(void)
+{
+ uartinit();
+ mmuinit();
+ l2init();
+ intrinit();
+ options();
+ confinit();
+ timerinit();
+ uartputs(" from Bell Labs\n", 16);
+ xinit();
+ printinit();
+ quotefmtinstall();
+ sanity();
+ todinit();
+ timersinit();
+ procinit0();
+ initseg();
+ if(delaylink)
+ bootlinks();
+ else
+ links();
+ archinit();
+ chandevreset();
+ pageinit();
+ swapinit();
+ screeninit();
+ userinit();
+ schedinit();
+}
--- /dev/null
+++ b/sys/src/9/zynq/mem.h
@@ -1,0 +1,124 @@
+/*
+ * Memory and machine-specific definitions. Used in C and assembler.
+ */
+
+#define MIN(a, b) ((a) < (b)? (a): (b))
+#define MAX(a, b) ((a) > (b)? (a): (b))
+
+/*
+ * 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 LINSIZ 32
+#define BLOCKALIGN LINSIZ
+#define FPalign 16
+
+#define MAXMACH 2
+#define KSTACK 4096
+
+#define HZ (1000)
+#define MS2HZ (1000/HZ)
+#define TK2SEC(t) ((t)/HZ)
+
+#define KZERO 0xF0000000
+#define KTZERO (KZERO+0x80000)
+#define VMAPSZ (SECSZ * 4)
+#define VMAP (KZERO - VMAPSZ)
+#define TMAPSZ SECSZ
+#define TMAP (VMAP - TMAPSZ)
+#define KMAPSZ SECSZ
+#define KMAP (TMAP - KMAPSZ)
+#define NKMAP (KMAPSZ / BY2PG - 1)
+#define MACHSIZE 8192
+#define MACH(n) (KZERO+(n)*MACHSIZE)
+#define MACHP(n) ((Mach *)MACH(n))
+#define CPU0L1 ROUND(MACH(MAXMACH), L1SZ)
+#define VMAPL2 (CPU0L1 + L1SZ)
+#define VMAPL2SZ (L2SZ * (VMAPSZ / SECSZ))
+#define TMAPL2(n) (VMAPL2 + VMAPL2SZ + (n) * L2SZ)
+#define TMAPL2SZ (MAXMACH * L2SZ)
+#define CONFSIZE 65536
+#define CONFADDR (KTZERO-CONFSIZE)
+
+#define UZERO 0
+#define UTZERO BY2PG
+#define UTROUND(t) ROUNDUP(t, BY2PG)
+#define USTKTOP 0xE0000000
+#define USTKSIZE (16*1024*1024)
+
+#define PTEMAPMEM (1024*1024)
+#define PTEPERTAB (PTEMAPMEM/BY2PG)
+#define SEGMAPSIZE 1984
+#define SSEGMAPSIZE 16
+
+#define PTEVALID L2VALID
+#define PTERONLY L2RONLY
+#define PTEWRITE L2WRITE
+#define PTEUNCACHED L2DEVICE
+#define PPN(x) ((x)&~(BY2PG-1))
+
+#define PsrDirq (1<<7)
+#define PsrDfiq (1<<6)
+#define PsrMask 0x1f
+#define PsrMusr 0x10
+#define PsrMfiq 0x11
+#define PsrMirq 0x12
+#define PsrMsvc 0x13
+#define PsrMabt 0x17
+#define PsrMiabt 0x16 /* not an actual mode; for ureg->type */
+#define PsrMund 0x1b
+
+#define DMB WORD $0xf57ff05f
+#define DSB WORD $0xf57ff04f
+#define ISB WORD $0xf57ff06f
+#define WFE WORD $0xe320f002
+#define CPS(m) WORD $(0xf1000000|(m))
+#define CPSMODE (1<<17)
+#define CPSIE (3<<6|2<<18)
+#define CPSID (3<<6|3<<18)
+#define Rmach 10
+#define Rup 9
+
+#define VMSR(c, r1, r2) WORD $(0x0ee00a10|(c)<<28|(r2)<<16|(r1)<<12)
+#define VMRS(c, r1, r2) WORD $(0x0ef00a10|(c)<<28|(r2)<<12|(r1)<<16)
+#define FPSID 0x0
+#define FPSCR 0x1
+#define MVFR1 0x6
+#define MVFR0 0x7
+#define FPEXC 0x8
+
+#define L1PT 1
+#define L1SEC (2|1<<10)
+#define L1DEVICE (1<<4)
+#define L1CACHED (1<<16|1<<14|1<<12|1<<2)
+#define L1KERRW 0
+#define L1SZ (4096*4)
+#define L2SZ (256*4)
+#define SECSZ 1048576
+#define SECSH 20
+#define NL2 256
+
+#define L1X(va) (((ulong)(va)) >> 20)
+#define L1RX(va) (((ulong)(va)) >> 20 & ~3)
+#define L2X(va) (((ulong)(va)) >> 12 & 0xff)
+#define L2RX(va) (((ulong)(va)) >> 12 & 0x3ff)
+
+#define L2VALID (2|1<<4)
+#define L2CACHED (1<<10|1<<8|1<<6|1<<2)
+#define L2DEVICE (1<<0)
+#define L2KERRW L2KERNEL
+#define L2KERNEL 0
+#define L2USER (1<<5)
+#define L2RONLY (1<<9)
+#define L2WRITE 0
+#define L2LOCAL (1<<11)
+
+#define TTBATTR (1<<6|1<<3)
--- /dev/null
+++ b/sys/src/9/zynq/mkfile
@@ -1,0 +1,92 @@
+CONF=zynq
+CONFLIST=zynq
+
+#must match mem.h
+KTZERO=0xf0080020
+
+objtype=arm
+</$objtype/mkfile
+p=9
+
+DEVS=`{rc ../port/mkdevlist $CONF}
+
+PORT=\
+ alarm.$O\
+ alloc.$O\
+ allocb.$O\
+ auth.$O\
+ cache.$O\
+ chan.$O\
+ dev.$O\
+ edf.$O\
+ fault.$O\
+ mul64fract.$O\
+ rebootcmd.$O\
+ page.$O\
+ parse.$O\
+ pgrp.$O\
+ portclock.$O\
+ print.$O\
+ proc.$O\
+ qio.$O\
+ qlock.$O\
+ segment.$O\
+ swap.$O\
+ sysfile.$O\
+ sysproc.$O\
+ taslock.$O\
+ tod.$O\
+ xalloc.$O\
+ random.$O\
+ rdb.$O\
+ syscallfmt.$O\
+
+OBJ=\
+ ltrap.$O\
+ l.$O\
+ main.$O\
+ mmu.$O\
+ trap.$O\
+ intr.$O\
+ timer.$O\
+ $CONF.root.$O\
+ $CONF.rootc.$O\
+ $DEVS\
+ $PORT\
+
+
+LIB=\
+ /$objtype/lib/libmemlayer.a\
+ /$objtype/lib/libmemdraw.a\
+ /$objtype/lib/libdraw.a\
+ /$objtype/lib/libip.a\
+ /$objtype/lib/libsec.a\
+ /$objtype/lib/libmp.a\
+ /$objtype/lib/libc.a\
+
+9:V: install # $p$CONF
+
+$p$CONF:D: $CONF.c $OBJ $LIB mkfile
+ $CC $CFLAGS '-DKERNDATE='`{date -n} $CONF.c
+ $LD -o $target -T$KTZERO -l $OBJ $CONF.$O $LIB
+
+<../boot/bootmkfile
+<../port/portmkfile
+<|../port/mkbootrules $CONF
+
+init.h:D: ../port/initcode.c init9.s
+ $CC ../port/initcode.c
+ $AS init9.s
+ $LD -l -R1 -s -o init.out init9.$O initcode.$O /arm/lib/libc.a
+ {echo 'uchar initcode[]={'
+ xd -1x <init.out |
+ sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
+ echo '};'} > init.h
+
+install:V: $p$CONF
+ cp $p$CONF /$objtype/
+ for(i in $EXTRACOPIES)
+ import $i / /n/$i && cp $p$CONF $p$CONF.gz /n/$i/$objtype/
+
+devusb.$O usbehci.$O usbehcizynq.$O: ../port/usb.h uncached.h
+usbehci.$O usbehcizynq.$O: usbehci.h
--- /dev/null
+++ b/sys/src/9/zynq/mmu.c
@@ -1,0 +1,422 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+ulong *mpcore, *slcr;
+
+void
+mmuinit(void)
+{
+ m->l1.pa = ttbget();
+ m->l1.va = KADDR(m->l1.pa);
+ mpcore = vmap(MPCORE_BASE, 0x2000);
+ slcr = vmap(SLCR_BASE, 0x1000);
+ m->l1.va[L1X(TMAP)] = PADDR(TMAPL2(m->machno)) | L1PT;
+ incref(&m->l1);
+}
+
+void
+l1switch(L1 *p, int flush)
+{
+ assert(!islo());
+
+ ttbput(p->pa);
+ if(flush){
+ if(++m->asid == 0)
+ flushtlb();
+ setasid(m->asid);
+ }
+}
+
+static L1 *
+l1alloc(void)
+{
+ L1 *p;
+ int s;
+
+ s = splhi();
+ if(m->l1free != nil){
+ p = m->l1free;
+ p->next = nil;
+ m->l1free = m->l1free->next;
+ m->nfree--;
+ splx(s);
+ return p;
+ }else{
+ p = smalloc(sizeof(L1));
+ for(;;){
+ p->va = mallocalign(L1SZ, L1SZ, 0, 0);
+ if(p->va != nil)
+ break;
+ if(!waserror()){
+ resrcwait("no memory for L1 table");
+ poperror();
+ }
+ }
+ memmove(p->va, m->l1.va, L1SZ);
+ p->pa = PADDR(p->va);
+ splx(s);
+ return p;
+ }
+}
+
+static void
+l1free(L1 *l1)
+{
+ if(islo())
+ panic("l1free: islo");
+ if(m->nfree >= 40){
+ free(l1->va);
+ free(l1);
+ }else{
+ l1->next = m->l1free;
+ m->l1free = l1;
+ m->nfree++;
+ }
+}
+
+static void
+upallocl1(void)
+{
+ L1 *p;
+ int s;
+
+ if(up->l1 != nil)
+ return;
+ p = l1alloc();
+ s = splhi();
+ if(up->l1 != nil)
+ l1free(p);
+ else{
+ up->l1 = p;
+ l1switch(p, 1);
+ }
+ splx(s);
+}
+
+static void
+l2free(Proc *proc)
+{
+ int s;
+ ulong *t;
+ Page *p, **l;
+
+ if(proc->l1 == nil || proc->mmuused == nil)
+ return;
+ s = splhi();
+ l = &proc->mmuused;
+ for(p = *l; p != nil; p = p->next){
+ t = proc->l1->va + p->daddr;
+ *t++ = 0;
+ *t++ = 0;
+ *t++ = 0;
+ *t = 0;
+ l = &p->next;
+ }
+ splx(s);
+ *l = proc->mmufree;
+ proc->mmufree = proc->mmuused;
+ proc->mmuused = 0;
+}
+
+void
+mmuswitch(Proc *p)
+{
+ if(p->newtlb){
+ p->newtlb = 0;
+ l2free(p);
+ }
+ if(p->l1 != nil)
+ l1switch(p->l1, 1);
+ else
+ l1switch(&m->l1, 1);
+}
+
+void
+putmmu(uintptr va, uintptr pa, Page *pg)
+{
+ Page *p;
+ ulong *e;
+ ulong *l2;
+ PTE old;
+ uintptr l2p;
+
+ if(up->l1 == nil)
+ upallocl1();
+ if((pa & PTEUNCACHED) == 0)
+ pa |= L2CACHED;
+ e = &up->l1->va[L1RX(va)];
+ if((*e & 3) == 0){
+ if(up->mmufree != nil){
+ p = up->mmufree;
+ up->mmufree = p->next;
+ }else
+ p = newpage(0, 0, 0);
+ l2p = p->pa;
+ l2 = tmpmap(l2p);
+ memset(l2, 0, BY2PG);
+ coherence();
+ e[0] = p->pa | L1PT;
+ e[1] = e[0] + L2SZ;
+ e[2] = e[1] + L2SZ;
+ e[3] = e[2] + L2SZ;
+ coherence();
+ p->daddr = L1RX(va);
+ p->next = up->mmuused;
+ up->mmuused = p;
+ }else{
+ l2p = *e & ~(BY2PG - 1);
+ l2 = tmpmap(l2p);
+ }
+ e = &l2[L2RX(va)];
+ old = *e;
+ *e = pa | L2VALID | L2USER | L2LOCAL;
+ tmpunmap(l2);
+ coherence();
+ if((old & L2VALID) != 0)
+ flushpg((void *) va);
+ if(pg->cachectl[0] == PG_TXTFLUSH){
+ cleandse((void *) va, (void *) (va + BY2PG));
+ invalise((void *) va, (void *) (va + BY2PG));
+ pg->cachectl[0] = PG_NOFLUSH;
+ }
+}
+
+void
+checkmmu(uintptr, uintptr)
+{
+ print("checkmmu\n");
+}
+
+void
+flushmmu(void)
+{
+ int s;
+
+ s = splhi();
+ up->newtlb = 1;
+ mmuswitch(up);
+ splx(s);
+}
+
+void
+mmurelease(Proc *proc)
+{
+ Page *p, *n;
+
+ if(islo())
+ panic("mmurelease: islo");
+
+ l1switch(&m->l1, 0);
+ if(proc->kmaptable != nil){
+ if(proc->l1 == nil)
+ panic("mmurelease: no l1");
+ if(decref(proc->kmaptable) != 0)
+ panic("mmurelease: kmap ref %ld", proc->kmaptable->ref);
+ if(proc->nkmap)
+ panic("mmurelease: nkmap %d", proc->nkmap);
+ if(PPN(proc->l1->va[L1X(KMAP)]) != proc->kmaptable->pa)
+ panic("mmurelease: bad kmap l2 %#.8lux kmap %#.8lux", proc->l1->va[L1X(KMAP)], proc->kmaptable->pa);
+ proc->l1->va[L1X(KMAP)] = 0;
+ pagechainhead(proc->kmaptable);
+ proc->kmaptable = nil;
+ }
+ if(proc->l1 != nil){
+ l2free(proc);
+ l1free(proc->l1);
+ proc->l1 = nil;
+ }
+ for(p = proc->mmufree; p != nil; p = n){
+ n = p->next;
+ if(decref(p) != 0)
+ panic("mmurelease: p->ref %ld", p->ref);
+ pagechainhead(p);
+ }
+ if(proc->mmufree != nil && palloc.r.p != nil)
+ wakeup(&palloc.r);
+ proc->mmufree = nil;
+}
+
+void
+countpagerefs(ulong *, int)
+{
+ print("countpagerefs\n");
+}
+
+void *
+kaddr(uintptr u)
+{
+ if(u >= (uintptr)-KZERO)
+ panic("kaddr: pa=%#.8lux", u);
+ return (void *)(u + KZERO);
+}
+
+uintptr
+paddr(void *v)
+{
+ if((uintptr)v < KZERO)
+ panic("paddr: va=%#.8lux", (uintptr) v);
+ return (uintptr)v - KZERO;
+}
+
+uintptr
+cankaddr(uintptr u)
+{
+ if(u >= (uintptr)-KZERO)
+ return 0;
+ return -KZERO - u;
+}
+
+KMap *
+kmap(Page *page)
+{
+ ulong *e, *v;
+ int i;
+ ulong s;
+
+ if(up == nil)
+ panic("kmap: up=0 pc=%#.8lux", getcallerpc(&page));
+ if(up->l1 == nil)
+ upallocl1();
+ if(up->nkmap < 0)
+ panic("kmap %lud %s: nkmap=%d", up->pid, up->text, up->nkmap);
+ s = splhi();
+ up->nkmap++;
+ e = &up->l1->va[L1X(KMAP)];
+ if((*e & 3) == 0){
+ if(up->kmaptable != nil)
+ panic("kmaptable");
+ spllo();
+ up->kmaptable = newpage(0, 0, 0);
+ splhi();
+ v = tmpmap(up->kmaptable->pa);
+ memset(v, 0, BY2PG);
+ v[0] = page->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL;
+ v[NKMAP] = up->kmaptable->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL;
+ tmpunmap(v);
+ coherence();
+ *e = up->kmaptable->pa | L1PT;
+ splx(s);
+ coherence();
+ return (KMap *) KMAP;
+ }
+ if(up->kmaptable == nil)
+ panic("kmaptable");
+ e = (ulong *) (KMAP + NKMAP * BY2PG);
+ for(i = 0; i < NKMAP; i++)
+ if((e[i] & 3) == 0){
+ e[i] = page->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL;
+ splx(s);
+ coherence();
+ return (KMap *) (KMAP + i * BY2PG);
+ }
+ panic("out of kmap");
+ return nil;
+}
+
+void
+kunmap(KMap *arg)
+{
+ uintptr va;
+ ulong *e;
+
+ va = (uintptr) arg;
+ if(up->l1 == nil || (up->l1->va[L1X(KMAP)] & 3) == 0)
+ panic("kunmap: no kmaps");
+ if(va < KMAP || va >= KMAP + NKMAP * BY2PG)
+ panic("kunmap: bad address %#.8lux pc=%#p", va, getcallerpc(&arg));
+ e = (ulong *) (KMAP + NKMAP * BY2PG) + L2X(va);
+ if((*e & 3) == 0)
+ panic("kunmap: not mapped %#.8lux pc=%#p", va, getcallerpc(&arg));
+ up->nkmap--;
+ if(up->nkmap < 0)
+ panic("kunmap %lud %s: nkmap=%d", up->pid, up->text, up->nkmap);
+ *e = 0;
+ coherence();
+ flushpg((void *) va);
+}
+
+void *
+tmpmap(ulong pa)
+{
+ ulong *u, *ub, *ue;
+ void *v;
+
+ if(cankaddr(pa))
+ return KADDR(pa);
+ ub = (ulong *) TMAPL2(m->machno);
+ ue = ub + NL2;
+ for(u = ub; u < ue; u++)
+ if((*u & 3) == 0){
+ *u = pa | L2VALID | L2CACHED | L2KERRW;
+ coherence();
+ v = (void *) ((u - ub) * BY2PG + TMAP);
+ return v;
+ }
+ panic("tmpmap: full (pa=%#.8lux)", pa);
+ return nil;
+}
+
+void
+tmpunmap(void *v)
+{
+ ulong *u;
+
+ if(v >= (void*) KZERO)
+ return;
+ if(v < (void*)TMAP || v >= (void*)(TMAP + TMAPSZ))
+ panic("tmpunmap: invalid address (va=%#.8lux)", (uintptr) v);
+ u = (ulong *) TMAPL2(m->machno) + L2X(v);
+ if((*u & 3) == 0)
+ panic("tmpunmap: double unmap (va=%#.8lux)", (uintptr) v);
+ *u = 0;
+ coherence();
+ flushpg(v);
+}
+
+void *
+vmap(uintptr pa, ulong sz)
+{
+ ulong np;
+ void *vr, *ve;
+ static ulong *vp = (ulong *) VMAPL2 + 1; /* first page is uart */
+
+ if((pa & BY2PG - 1) != 0)
+ panic("vmap: misaligned pa=%#.8lux", pa);
+ np = (sz + BY2PG - 1) >> PGSHIFT;
+ vr = (char*) VMAP + (vp - (ulong *)VMAPL2 << PGSHIFT);
+ ve = (ulong *) (VMAPL2 + VMAPL2SZ);
+ while(np-- != 0){
+ if(vp == ve)
+ panic("vmap: out of vmap space (pa=%#.8lux)", pa);
+ *vp++ = pa | L2VALID | L2DEVICE | L2KERRW;
+ pa += BY2PG;
+ }
+ coherence();
+ return vr;
+}
+
+/* nasty things happen when there are cache entries for uncached memory
+ so must make sure memory is not mapped ANYWHERE cached */
+uintptr
+ualloc(ulong len, void **va)
+{
+ static uintptr free = OCM_BASE;
+ uintptr pa;
+
+ if(len == 0)
+ panic("ualloc: len == 0");
+ len = PGROUND(len);
+ if(free + len < OCM_BASE)
+ panic("ualloc: out of uncached memory");
+ pa = free;
+ free += len;
+ if(va != nil){
+ *va = vmap(pa, len);
+ invaldse(*va, (char *) *va + len);
+ }
+ return pa;
+}
--- /dev/null
+++ b/sys/src/9/zynq/screen.c
@@ -1,0 +1,126 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+
+#define Image IMAGE
+#include <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#include "screen.h"
+
+Cursor arrow = {
+ { -1, -1 },
+ { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
+ 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
+ 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
+ 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
+ },
+ { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
+ 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
+ 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
+ 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
+ },
+};
+
+Memimage *gscreen;
+static Memdata xgdata;
+
+static Memimage xgscreen =
+{
+ { 0, 0, 800, 600 }, /* r */
+ { 0, 0, 800, 600 }, /* clipr */
+ 24, /* depth */
+ 3, /* nchan */
+ BGR24, /* chan */
+ nil, /* cmap */
+ &xgdata, /* data */
+ 0, /* zero */
+ 0, /* width in words of a single scan line */
+ 0, /* layer */
+ 0, /* flags */
+};
+
+void
+cursoron(void)
+{
+}
+
+void
+cursoroff(void)
+{
+}
+
+void
+setcursor(Cursor*)
+{
+}
+
+void
+flushmemscreen(Rectangle)
+{
+}
+
+void
+drawflushreal(void)
+{
+ uchar *fb, *fbe;
+
+ fb = xgdata.bdata;
+ fbe = fb + Dx(xgscreen.r) * Dy(xgscreen.r) * 3;
+ cleandse(fb, fbe);
+ clean2pa(PADDR(fb), PADDR(fbe));
+}
+
+void
+screeninit(void)
+{
+ uchar *fb;
+
+ fb = xspanalloc(Dx(xgscreen.r) * Dy(xgscreen.r) * 3, 64, 0);
+ print("%x\n", PADDR(fb));
+ memsetchan(&xgscreen, BGR24);
+ conf.monitor = 1;
+ xgdata.bdata = fb;
+ xgdata.ref = 1;
+ gscreen = &xgscreen;
+ gscreen->width = wordsperline(gscreen->r, gscreen->depth);
+
+ memimageinit();
+}
+
+uchar*
+attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
+{
+ *r = gscreen->r;
+ *d = gscreen->depth;
+ *chan = gscreen->chan;
+ *width = gscreen->width;
+ *softscreen = 0;
+
+ return gscreen->data->bdata;
+}
+
+void
+getcolor(ulong, ulong *, ulong *, ulong *)
+{
+}
+
+int
+setcolor(ulong, ulong, ulong, ulong)
+{
+ return 0;
+}
+
+void
+blankscreen(int)
+{
+}
+
+void
+mousectl(Cmdbuf *)
+{
+}
--- /dev/null
+++ b/sys/src/9/zynq/screen.h
@@ -1,0 +1,44 @@
+typedef struct Cursor Cursor;
+typedef struct Cursorinfo Cursorinfo;
+struct Cursorinfo {
+ Cursor;
+ Lock;
+};
+
+/* devmouse.c */
+extern void mousetrack(int, int, int, int);
+extern void absmousetrack(int, int, int, int);
+extern Point mousexy(void);
+
+extern void mouseaccelerate(int);
+extern int m3mouseputc(Queue*, int);
+extern int m5mouseputc(Queue*, int);
+extern int mouseputc(Queue*, int);
+
+extern Cursorinfo cursor;
+extern Cursor arrow;
+
+/* mouse.c */
+extern void mousectl(Cmdbuf*);
+extern void mouseresize(void);
+extern void mouseredraw(void);
+
+/* screen.c */
+extern void blankscreen(int);
+extern void flushmemscreen(Rectangle);
+extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*);
+extern void cursoron(void);
+extern void cursoroff(void);
+extern void setcursor(Cursor*);
+
+/* devdraw.c */
+extern QLock drawlock;
+
+#define ishwimage(i) 1 /* for ../port/devdraw.c */
+
+/* swcursor.c */
+void swcursorhide(void);
+void swcursoravoid(Rectangle);
+void swcursordraw(Point);
+void swcursorload(Cursor *);
+void swcursorinit(void);
--- /dev/null
+++ b/sys/src/9/zynq/timer.c
@@ -1,0 +1,91 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+enum {
+ TIMERDIV = 1,
+ LTIMERDIV = 1,
+
+ ARM_PLL_CTRL = 0x100/4,
+ ARM_CLK_CTRL = 0x120/4,
+
+ GTIMERVALL = 0x200/4,
+ GTIMERVALH,
+ GTIMERCTL,
+ LTIMERVAL = 0x604/4,
+ LTIMERCTL,
+ LTIMERISR,
+};
+
+uvlong timerhz;
+
+void
+delay(int)
+{
+}
+
+void
+microdelay(int)
+{
+}
+
+uvlong
+fastticks(uvlong *hz)
+{
+ ulong lo, hi;
+
+ if(hz != nil)
+ *hz = timerhz;
+ do{
+ hi = mpcore[GTIMERVALH];
+ lo = mpcore[GTIMERVALL];
+ }while(hi != mpcore[GTIMERVALH]);
+ return lo | (uvlong)hi << 32;
+}
+
+ulong
+µs(void)
+{
+ NOPE
+ return 0;
+}
+
+void
+timerset(Tval v)
+{
+ vlong w;
+
+ w = v - fastticks(nil);
+ if(w < 1)
+ w = 1;
+ if(w > 0xffffffffLL)
+ w = 0xffffffff;
+ mpcore[LTIMERCTL] &= ~1;
+ mpcore[LTIMERVAL] = w;
+ mpcore[LTIMERCTL] |= 1;
+}
+
+void
+timerirq(Ureg *u, void *)
+{
+ if((mpcore[LTIMERISR] & 1) != 0){
+ mpcore[LTIMERISR] |= 1;
+ timerintr(u, 0);
+ }
+}
+
+void
+timerinit(void)
+{
+ int mhz;
+
+ mhz = PS_CLK * (slcr[ARM_PLL_CTRL] >> 12 & 0x7f) / (slcr[ARM_CLK_CTRL] >> 8 & 0x3f);
+ timerhz = mhz * 500000;
+ mpcore[GTIMERCTL] = TIMERDIV - 1 << 8 | 3;
+ mpcore[LTIMERCTL] = LTIMERDIV - 1 << 8 | 4;
+ intrenable(TIMERIRQ, timerirq, nil, EDGE, "clock");
+ setpmcr(7);
+}
--- /dev/null
+++ b/sys/src/9/zynq/trap.c
@@ -1,0 +1,544 @@
+#include "u.h"
+#include <ureg.h>
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "tos.h"
+
+static void
+_dumpstack(Ureg *ureg)
+{
+ uintptr l, v, i, estack;
+ extern ulong etext;
+ int x;
+ char *s;
+
+ if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
+ iprint("dumpstack disabled\n");
+ return;
+ }
+ iprint("dumpstack\n");
+
+ x = 0;
+ x += iprint("ktrace /arm/9zynq %.8lux %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp, ureg->r14);
+ i = 0;
+ if(up
+ && (uintptr)&l >= (uintptr)up->kstack
+ && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
+ estack = (uintptr)up->kstack+KSTACK;
+ else if((uintptr)&l >= (uintptr)m->stack
+ && (uintptr)&l <= (uintptr)m+MACHSIZE)
+ estack = (uintptr)m+MACHSIZE;
+ else
+ return;
+ x += iprint("estackx %p\n", estack);
+
+ for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
+ v = *(uintptr*)l;
+ if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){
+ x += iprint("%.8p=%.8p ", l, v);
+ i++;
+ }
+ if(i == 4){
+ i = 0;
+ x += iprint("\n");
+ }
+ }
+ if(i)
+ iprint("\n");
+ iprint("EOF\n");
+}
+
+static void
+faultarm(Ureg *ureg, ulong fsr, uintptr addr)
+{
+ int user, insyscall, read, n;
+ static char buf[ERRMAX];
+
+ read = (fsr & (1<<11)) == 0;
+ user = userureg(ureg);
+ if(!user){
+ if(addr >= USTKTOP || up == nil)
+ _dumpstack(ureg);
+ if(addr >= USTKTOP)
+ panic("kernel fault: bad address pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr);
+ if(up == nil)
+ panic("kernel fault: no user process pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr);
+ }
+ if(up == nil)
+ panic("user fault: up=nil pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr);
+ insyscall = up->insyscall;
+ up->insyscall = 1;
+ n = fault(addr, read);
+ if(n < 0){
+ if(!user){
+ dumpregs(ureg);
+ _dumpstack(ureg);
+ panic("kernel fault: pc=%#.8lux addr=%#.8lux fsr=%#.8lux", ureg->pc, addr, fsr);
+ }
+ sprint(buf, "sys: trap: fault %s addr=%#.8lux", read ? "read" : "write", addr);
+ postnote(up, 1, buf, NDebug);
+ }
+ up->insyscall = insyscall;
+}
+
+static void
+mathtrap(Ureg *, ulong)
+{
+ if((up->fpstate & FPillegal) != 0){
+ postnote(up, 1, "sys: floating point in note handler", NDebug);
+ return;
+ }
+ switch(up->fpstate){
+ case FPinit:
+ fpinit();
+ up->fpstate = FPactive;
+ break;
+ case FPinactive:
+ fprestore(&up->fpsave);
+ up->fpstate = FPactive;
+ break;
+ case FPactive:
+ postnote(up, 1, "sys: floating point error", NDebug);
+ break;
+ }
+}
+
+void
+trap(Ureg *ureg)
+{
+ int user;
+ ulong opc, cp;
+
+ user = userureg(ureg);
+ if(user){
+ if(up == nil)
+ panic("user trap: up=nil");
+ up->dbgreg = ureg;
+ cycles(&up->kentry);
+ }
+ switch(ureg->type){
+ case PsrMund:
+ ureg->pc -= 4;
+ if(user){
+ spllo();
+ if(okaddr(ureg->pc, 4, 0)){
+ opc = *(ulong*)ureg->pc;
+ if((opc & 0x0f000000) == 0x0e000000 || (opc & 0x0e000000) == 0x0c000000){
+ cp = opc >> 8 & 15;
+ if(cp == 10 || cp == 11){
+ mathtrap(ureg, opc);
+ break;
+ }
+ }
+ }
+ postnote(up, 1, "sys: trap: invalid opcode", NDebug);
+ break;
+ }
+ panic("invalid opcode at pc=%#.8lux lr=%#.8lux", ureg->pc, ureg->r14);
+ break;
+ case PsrMiabt:
+ ureg->pc -= 4;
+ faultarm(ureg, getifsr(), getifar());
+ break;
+ case PsrMabt:
+ ureg->pc -= 8;
+ faultarm(ureg, getdfsr(), getdfar());
+ break;
+ case PsrMirq:
+ ureg->pc -= 4;
+ intr(ureg);
+ break;
+ default:
+ print("unknown trap type %ulx\n", ureg->type);
+ }
+ splhi();
+ if(user){
+ if(up->procctl || up->nnote)
+ notify(ureg);
+ kexit(ureg);
+ }
+}
+
+#include "../port/systab.h"
+
+void
+syscall(Ureg *ureg)
+{
+ char *e;
+ uintptr sp;
+ long ret;
+ int i, s;
+ ulong scallnr;
+ vlong startns, stopns;
+
+ if(!userureg(ureg))
+ panic("syscall: pc=%#.8lux", ureg->pc);
+
+ cycles(&up->kentry);
+
+ m->syscall++;
+ up->insyscall = 1;
+ up->pc = ureg->pc;
+ up->dbgreg = ureg;
+
+ sp = ureg->sp;
+ up->scallnr = scallnr = ureg->r0;
+
+ spllo();
+
+ up->nerrlab = 0;
+ ret = -1;
+ if(!waserror()){
+ if(sp < USTKTOP - BY2PG || sp > USTKTOP - sizeof(Sargs) - BY2WD){
+ validaddr(sp, sizeof(Sargs)+BY2WD, 0);
+ evenaddr(sp);
+ }
+ up->s = *((Sargs*) (sp + BY2WD));
+
+ if(up->procctl == Proc_tracesyscall){
+ syscallfmt(scallnr, ureg->pc, (va_list) up->s.args);
+ s = splhi();
+ up->procctl = Proc_stopme;
+ procctl(up);
+ splx(s);
+ startns = todget(nil);
+ }
+
+ if(scallnr >= nsyscall || systab[scallnr] == 0){
+ pprint("bad sys call number %lud pc %lux", scallnr, ureg->pc);
+ postnote(up, 1, "sys: bad sys call", NDebug);
+ error(Ebadarg);
+ }
+ up->psstate = sysctab[scallnr];
+ ret = systab[scallnr]((va_list)up->s.args);
+ poperror();
+ }else{
+ e = up->syserrstr;
+ up->syserrstr = up->errstr;
+ up->errstr = e;
+ }
+ if(up->nerrlab){
+ print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
+ for(i = 0; i < NERR; i++)
+ print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
+ panic("error stack");
+ }
+
+ ureg->r0 = ret;
+ if(up->procctl == Proc_tracesyscall){
+ stopns = todget(nil);
+ sysretfmt(scallnr, (va_list) up->s.args, ret, startns, stopns);
+ s = splhi();
+ up->procctl = Proc_stopme;
+ procctl(up);
+ splx(s);
+ }
+
+ up->insyscall = 0;
+ up->psstate = 0;
+ if(scallnr == NOTED)
+ noted(ureg, *((ulong *) up->s.args));
+
+ if(scallnr != RFORK && (up->procctl || up->nnote)){
+ splhi();
+ notify(ureg);
+ }
+ if(up->delaysched)
+ sched();
+ kexit(ureg);
+ splhi();
+}
+
+int
+notify(Ureg *ureg)
+{
+ int l;
+ ulong s, sp;
+ Note *n;
+
+ if(up->procctl)
+ procctl(up);
+ if(up->nnote == 0)
+ return 0;
+
+ if(up->fpstate == FPactive){
+ fpsave(&up->fpsave);
+ up->fpstate = FPinactive;
+ }
+ up->fpstate |= FPillegal;
+
+ 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 > ERRMAX-15) /* " pc=0x12345678\0" */
+ l = ERRMAX-15;
+ sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
+ }
+
+ if(n->flag!=NUser && (up->notified || up->notify==0)){
+ qunlock(&up->debug);
+ if(n->flag == NDebug)
+ pprint("suicide: %s\n", n->msg);
+ 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 = ureg->sp;
+ sp -= 256; /* debugging: preserve context causing problem */
+ sp -= sizeof(Ureg);
+
+ if(!okaddr((uintptr)up->notify, 1, 0)
+ || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)
+ || ((uintptr) up->notify & 3) != 0
+ || (sp & 3) != 0){
+ qunlock(&up->debug);
+ pprint("suicide: bad address in notify\n");
+ pexit("Suicide", 0);
+ }
+
+ memmove((Ureg*)sp, ureg, sizeof(Ureg));
+ *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
+ up->ureg = (void*)sp;
+ sp -= BY2WD+ERRMAX;
+ memmove((char*)sp, up->note[0].msg, ERRMAX);
+ sp -= 3*BY2WD;
+ *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;
+ *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;
+ ureg->r0 = (uintptr) up->ureg;
+ ureg->sp = sp;
+ ureg->pc = (uintptr) up->notify;
+ ureg->r14 = 0;
+ 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;
+}
+
+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;
+ up->fpstate &= ~FPillegal;
+
+ oureg = (ulong) nureg;
+ if(!okaddr(oureg - BY2WD, BY2WD + sizeof(Ureg), 0) || (oureg & 3) != 0){
+ qunlock(&up->debug);
+ pprint("bad ureg in noted or call to noted when not notified\n");
+ pexit("Suicide", 0);
+ }
+
+ nureg->psr = nureg->psr & 0xf80f0000 | ureg->psr & 0x07f0ffff;
+
+ memmove(ureg, nureg, sizeof(Ureg));
+
+ switch(arg0){
+ case NCONT: case NRSTR:
+ if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) ||
+ (nureg->pc & 3) != 0 || (nureg->sp & 3) != 0){
+ qunlock(&up->debug);
+ pprint("suicide: trap in noted\n");
+ pexit("Suicide", 0);
+ }
+ up->ureg = (Ureg *) (*(ulong *) (oureg - BY2WD));
+ qunlock(&up->debug);
+ break;
+
+ case NSAVE:
+ if(!okaddr(nureg->pc, BY2WD, 0) || !okaddr(nureg->sp, BY2WD, 0) ||
+ (nureg->pc & 3) != 0 || (nureg->sp & 3) != 0){
+ qunlock(&up->debug);
+ pprint("suicide: trap in noted\n");
+ pexit("Suicide", 0);
+ }
+ qunlock(&up->debug);
+ sp = oureg - 4 * BY2WD - ERRMAX;
+ splhi();
+ ureg->sp = sp;
+ ((ulong *) sp)[1] = oureg;
+ ((ulong *) sp)[0] = 0;
+ break;
+
+ default:
+ up->lastnote.flag = NDebug;
+
+ case NDFLT:
+ qunlock(&up->debug);
+ if(up->lastnote.flag == NDebug)
+ pprint("suicide: %s\n", up->lastnote.msg);
+ pexit(up->lastnote.msg, up->lastnote.flag != NDebug);
+ }
+}
+
+
+void
+dumpstack(void)
+{
+ callwithureg(_dumpstack);
+}
+
+void
+dumpregs(Ureg *)
+{
+ print("dumpregs\n");
+}
+
+void
+setkernur(Ureg *ureg, Proc *p)
+{
+ ureg->pc = p->sched.pc;
+ ureg->sp = p->sched.sp + 4;
+ ureg->r14 = (uintptr) sched;
+}
+
+void
+setregisters(Ureg* ureg, char* pureg, char* uva, int n)
+{
+ ulong v;
+
+ v = ureg->psr;
+ memmove(pureg, uva, n);
+ ureg->psr = ureg->psr & 0xf80f0000 | v & 0x07f0ffff;
+}
+
+void
+callwithureg(void (*f) (Ureg *))
+{
+ Ureg u;
+
+ u.pc = getcallerpc(&f);
+ u.sp = (uintptr) &f - 4;
+ f(&u);
+}
+
+uintptr
+userpc(void)
+{
+ Ureg *ur;
+
+ ur = up->dbgreg;
+ return ur->pc;
+}
+
+uintptr
+dbgpc(Proc *)
+{
+ Ureg *ur;
+
+ ur = up->dbgreg;
+ if(ur == nil)
+ return 0;
+ return ur->pc;
+}
+
+void
+procsave(Proc *p)
+{
+ uvlong t;
+
+ if(p->fpstate == FPactive){
+ if(p->state == Moribund)
+ fpclear();
+ else
+ fpsave(&p->fpsave);
+ p->fpstate = FPinactive;
+ }
+ cycles(&t);
+ p->kentry -= t;
+ p->pcycles += t;
+
+ l1switch(&m->l1, 0);
+}
+
+void
+procrestore(Proc *p)
+{
+ uvlong t;
+
+ if(p->kp)
+ return;
+
+ cycles(&t);
+ p->kentry += t;
+ p->pcycles -= t;
+}
+
+static void
+linkproc(void)
+{
+ spllo();
+ up->kpfun(up->kparg);
+ pexit("kproc dying", 0);
+}
+
+void
+kprocchild(Proc* p, void (*func)(void*), void* arg)
+{
+ p->sched.pc = (uintptr) linkproc;
+ p->sched.sp = (uintptr) p->kstack + KSTACK;
+
+ p->kpfun = func;
+ p->kparg = arg;
+}
+
+void
+forkchild(Proc *p, Ureg *ureg)
+{
+ Ureg *cureg;
+
+ p->sched.pc = (uintptr) forkret;
+ p->sched.sp = (uintptr) p->kstack + KSTACK - sizeof(Ureg);
+
+ cureg = (Ureg*) p->sched.sp;
+ memmove(cureg, ureg, sizeof(Ureg));
+ cureg->r0 = 0;
+
+ p->psstate = 0;
+ p->insyscall = 0;
+}
+
+uintptr
+execregs(uintptr entry, ulong ssize, ulong nargs)
+{
+ ulong *sp;
+ Ureg *ureg;
+
+ sp = (ulong*)(USTKTOP - ssize);
+ *--sp = nargs;
+
+ ureg = up->dbgreg;
+ ureg->sp = (uintptr) sp;
+ ureg->pc = entry;
+ ureg->r14 = 0;
+ return USTKTOP-sizeof(Tos);
+}
--- /dev/null
+++ b/sys/src/9/zynq/uartzynq.c
@@ -1,0 +1,244 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+enum {
+ CTRL = 0,
+ MODE,
+ IRQEN,
+ IRQDIS,
+ MASK,
+ INTSTAT,
+ RXFIFOLVL = 0x20/4,
+ CHANSTAT = 0x2C/4,
+ FIFO = 0x30/4,
+};
+
+enum {
+ TXFULL = 1<<4,
+ TXEMPTY = 1<<3,
+ RXEMPTY = 1<<1,
+ RXTRIG = 1<<0,
+};
+
+typedef struct Ctlr {
+ Lock;
+ ulong *r;
+ int irq, iena;
+} Ctlr;
+
+Uart* uartenable(Uart *);
+
+extern PhysUart zynqphysuart;
+
+static Ctlr zctlr[1] = {
+ {
+ .r = (void *) VMAP,
+ .irq = UART1IRQ,
+ }
+};
+
+static Uart zuart[1] = {
+ {
+ .regs = &zctlr[0],
+ .name = "UART1",
+ .freq = 25000000,
+ .phys = &zynqphysuart,
+ .console = 1,
+ .baud = 115200,
+ }
+};
+
+void
+uartinit(void)
+{
+ consuart = zuart;
+}
+
+static Uart *
+zuartpnp(void)
+{
+ return zuart;
+}
+
+static void
+zuartkick(Uart *uart)
+{
+ Ctlr *ct;
+ int i;
+
+ if(uart->blocked)
+ return;
+ ct = uart->regs;
+ for(i = 0; i < 128; i++){
+ if((ct->r[CHANSTAT] & TXFULL) != 0)
+ break;
+ if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
+ break;
+ ct->r[FIFO] = *uart->op++;
+ }
+}
+
+static void
+zuartintr(Ureg *, void *arg)
+{
+ Uart *uart;
+ Ctlr *ct;
+ int c;
+ ulong fl;
+
+ uart = arg;
+ ct = uart->regs;
+ fl = ct->r[INTSTAT] & ct->r[MASK];
+ ct->r[INTSTAT] = fl;
+ if((fl & RXTRIG) != 0)
+ while((ct->r[CHANSTAT] & RXEMPTY) == 0){
+ c = ct->r[FIFO];
+ uartrecv(uart, c);
+ }
+ if((fl & TXEMPTY) != 0)
+ zuartkick(uart);
+}
+
+static void
+zuartenable(Uart *uart, int ie)
+{
+ Ctlr *ctlr;
+
+ ctlr = uart->regs;
+ ilock(ctlr);
+ while((ctlr->r[CHANSTAT] & TXEMPTY) == 0)
+ ;
+ ctlr->r[IRQDIS] = -1;
+ ctlr->r[RXFIFOLVL] = 1;
+ if(ie){
+ if(!ctlr->iena){
+ intrenable(ctlr->irq, zuartintr, uart, LEVEL, uart->name);
+ ctlr->iena = 1;
+ }
+ ctlr->r[IRQEN] = RXTRIG | TXEMPTY;
+ }
+ iunlock(ctlr);
+}
+
+static int
+zuartgetc(Uart *uart)
+{
+ Ctlr *c;
+
+ c = uart->regs;
+ while((c->r[CHANSTAT] & RXEMPTY) != 0)
+ ;
+ return c->r[FIFO];
+}
+
+static void
+zuartputc(Uart *uart, int c)
+{
+ Ctlr *ct;
+
+ ct = uart->regs;
+ while((ct->r[CHANSTAT] & TXFULL) != 0)
+ ;
+ ct->r[FIFO] = c;
+ return;
+}
+
+int
+uartconsole(void)
+{
+ Uart *uart = zuart;
+
+ if(up == nil)
+ return -1;
+
+ if(uartenable(uart) != nil){
+ serialoq = uart->oq;
+ uart->opens++;
+ consuart = uart;
+ }
+ return 0;
+}
+
+int
+zuartbits(Uart *uart, int n)
+{
+ Ctlr *ct;
+
+ ct = uart->regs;
+ ct->r[MODE] &= ~6;
+ switch(n){
+ case 8:
+ return 0;
+ case 7:
+ ct->r[MODE] |= 4;
+ return 0;
+ case 6:
+ ct->r[MODE] |= 6;
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+int
+zuartbaud(Uart *, int n)
+{
+ print("uart baud %d\n", n);
+ return 0;
+}
+
+int
+zuartparity(Uart *uart, int p)
+{
+ Ctlr *ct;
+
+ ct = uart->regs;
+ switch(p){
+ case 'o':
+ ct->r[MODE] = ct->r[MODE] & ~0x38 | 0x08;
+ return 0;
+ case 'e':
+ ct->r[MODE] = ct->r[MODE] & ~0x38;
+ return 0;
+ case 'n':
+ ct->r[MODE] = ct->r[MODE] & 0x38 | 0x20;
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+void
+zuartnop(Uart *, int)
+{
+}
+
+int
+zuartnope(Uart *, int)
+{
+ return -1;
+}
+
+
+PhysUart zynqphysuart = {
+ .pnp = zuartpnp,
+ .enable = zuartenable,
+ .kick = zuartkick,
+ .getc = zuartgetc,
+ .putc = zuartputc,
+ .bits = zuartbits,
+ .baud = zuartbaud,
+ .parity = zuartparity,
+
+ .stop = zuartnope,
+ .rts = zuartnop,
+ .dtr = zuartnop,
+ .dobreak = zuartnop,
+ .fifo = zuartnop,
+ .power = zuartnop,
+ .modemctl = zuartnop,
+};
--- /dev/null
+++ b/sys/src/9/zynq/uncached.h
@@ -1,0 +1,27 @@
+#define free ucfree
+#define malloc myucalloc
+#define mallocz ucallocz
+#define smalloc myucalloc
+#define xspanalloc ucallocalign
+
+#define allocb ucallocb
+#define iallocb uciallocb
+#define freeb ucfreeb
+
+static void *
+ucallocz(uint n, int)
+{
+ char *p = ucalloc(n);
+
+ if (p)
+ memset(p, 0, n);
+ else
+ panic("ucalloc: out of memory");
+ return p;
+}
+
+static void *
+myucalloc(uint n)
+{
+ return ucallocz(n, 1);
+}
--- /dev/null
+++ b/sys/src/9/zynq/usbehci.h
@@ -1,0 +1,141 @@
+/* override default macros from ../port/usb.h */
+#undef dprint
+#undef ddprint
+#undef deprint
+#undef ddeprint
+#define dprint if(ehcidebug)print
+#define ddprint if(ehcidebug>1)print
+#define deprint if(ehcidebug || ep->debug)print
+#define ddeprint if(ehcidebug>1 || ep->debug>1)print
+
+enum {
+ /* typed links */
+ Lterm = 1,
+ Litd = 0<<1,
+ Lqh = 1<<1,
+ Lsitd = 2<<1,
+ Lfstn = 3<<1, /* we don't use these */
+
+ /* Cmd reg. */
+ Cstop = 0x00000, /* stop running */
+ Crun = 0x00001, /* start operation */
+ Chcreset = 0x00002, /* host controller reset */
+ Cflsmask = 0x0000C, /* frame list size bits */
+ Cfls1024 = 0x00000, /* frame list size 1024 */
+ Cfls512 = 0x00004, /* frame list size 512 frames */
+ Cfls256 = 0x00008, /* frame list size 256 frames */
+ Cpse = 0x00010, /* periodic sched. enable */
+ Case = 0x00020, /* async sched. enable */
+ Ciasync = 0x00040, /* interrupt on async advance doorbell */
+ Citc1 = 0x10000, /* interrupt threshold ctl. 1 µframe */
+ Citc4 = 0x40000, /* same. 2 µframes */
+ /* ... */
+ Citc8 = 0x80000, /* same. 8 µframes (can go up to 64) */
+
+ /* Sts reg. */
+ Sasyncss = 0x08000, /* aync schedule status */
+ Speriodss = 0x04000, /* periodic schedule status */
+ Srecl = 0x02000, /* reclamnation (empty async sched.) */
+ Shalted = 0x01000, /* h.c. is halted */
+ Sasync = 0x00020, /* interrupt on async advance */
+ Sherr = 0x00010, /* host system error */
+ Sfrroll = 0x00008, /* frame list roll over */
+ Sportchg = 0x00004, /* port change detect */
+ Serrintr = 0x00002, /* error interrupt */
+ Sintr = 0x00001, /* interrupt */
+ Sintrs = 0x0003F, /* interrupts status */
+
+ /* Portsc reg. */
+ Pspresent = 0x00000001, /* device present */
+ Psstatuschg = 0x00000002, /* Pspresent changed */
+ Psenable = 0x00000004, /* device enabled */
+ Pschange = 0x00000008, /* Psenable changed */
+ Psresume = 0x00000040, /* resume detected */
+ Pssuspend = 0x00000080, /* port suspended */
+ Psreset = 0x00000100, /* port reset */
+ Pspower = 0x00001000, /* port power on */
+
+ /* Intr reg. */
+ Iusb = 0x01, /* intr. on usb */
+ Ierr = 0x02, /* intr. on usb error */
+ Iportchg = 0x04, /* intr. on port change */
+ Ifrroll = 0x08, /* intr. on frlist roll over */
+ Ihcerr = 0x10, /* intr. on host error */
+ Iasync = 0x20, /* intr. on async advance enable */
+ Iall = 0x3F, /* all interrupts */
+
+ Callmine = 1,
+
+ /* hack to disable port handoff */
+ Psowner = 0,
+ Pslinemask = 0,
+ Pslow = -1
+};
+
+typedef struct Ctlr Ctlr;
+typedef void Ecapio;
+typedef struct Eopio Eopio;
+typedef struct Isoio Isoio;
+typedef struct Poll Poll;
+typedef struct Qh Qh;
+typedef struct Qtree Qtree;
+
+#pragma incomplete Ctlr
+
+struct Eopio
+{
+ ulong cmd;
+ ulong sts;
+ ulong intr;
+ ulong frno;
+ ulong dummy1[2];
+ ulong frbase;
+ ulong link;
+ ulong dummy2[9];
+ ulong config;
+ ulong portsc[1];
+};
+
+struct Poll
+{
+ Lock;
+ Rendez;
+ int must;
+ int does;
+};
+
+struct Ctlr
+{
+ Rendez; /* for waiting to async advance doorbell */
+ Lock; /* for ilock. qh lists and basic ctlr I/O */
+ QLock portlck; /* for port resets/enable... (and doorbell) */
+ int active; /* in use or not */
+ void* capio; /* base address for debug info */
+ Eopio* opio; /* Operational i/o regs */
+
+ int nframes; /* 1024, 512, or 256 frames in the list */
+ ulong* frames; /* periodic frame list (hw) */
+ Qh* qhs; /* async Qh circular list for bulk/ctl */
+ Qtree* tree; /* tree of Qhs for the periodic list */
+ int ntree; /* number of dummy qhs in tree */
+ Qh* intrqhs; /* list of (not dummy) qhs in tree */
+ Isoio* iso; /* list of active Iso I/O */
+ ulong load;
+ ulong isoload;
+ int nintr; /* number of interrupts attended */
+ int ntdintr; /* number of intrs. with something to do */
+ int nqhintr; /* number of async td intrs. */
+ int nisointr; /* number of periodic td intrs. */
+ int nreqs;
+ Poll poll;
+
+ ulong base;
+ int irq;
+ ulong* r;
+};
+
+extern int ehcidebug;
+
+void ehcilinkage(Hci *hp);
+void ehcimeminit(Ctlr *ctlr);
+void ehcirun(Ctlr *ctlr, int on);
--- /dev/null
+++ b/sys/src/9/zynq/usbehcizynq.c
@@ -1,0 +1,103 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "../port/usb.h"
+#include "usbehci.h"
+
+enum {
+ USBMODE = 0x1A8/4,
+ USBHOST = 3,
+ OTGSC = 0x1A4/4,
+ ULPI = 0x170/4,
+};
+
+static Ctlr ctlrs[3] = {
+ {
+ .base = USB0_BASE,
+ .irq = USB0IRQ,
+ },
+ {
+ .base = USB1_BASE,
+ .irq = USB1IRQ,
+ },
+};
+
+static void
+ehcireset(Ctlr *ctlr)
+{
+ int i;
+ Eopio *opio;
+
+ ilock(ctlr);
+ opio = ctlr->opio;
+ ehcirun(ctlr, 0);
+ opio->cmd |= Chcreset;
+ for(i = 0; i < 100; i++){
+ if((opio->cmd & Chcreset) == 0)
+ break;
+ delay(1);
+ }
+ if(i == 100)
+ print("ehci %#p controller reset timed out\n", ctlr->base);
+ opio->cmd |= Citc1;
+ switch(opio->cmd & Cflsmask){
+ case Cfls1024:
+ ctlr->nframes = 1024;
+ break;
+ case Cfls512:
+ ctlr->nframes = 512;
+ break;
+ case Cfls256:
+ ctlr->nframes = 256;
+ break;
+ default:
+ panic("ehci: unknown fls %ld", opio->cmd & Cflsmask);
+ }
+ dprint("ehci: %d frames\n", ctlr->nframes);
+ iunlock(ctlr);
+}
+
+static int
+reset(Hci *hp)
+{
+ static Lock resetlck;
+ Ctlr *ctlr;
+
+ ilock(&resetlck);
+ for(ctlr = ctlrs; ctlr->base != 0; ctlr++)
+ if(!ctlr->active && (hp->port == 0 || hp->port == ctlr->base)){
+ ctlr->active = 1;
+ break;
+ }
+ iunlock(&resetlck);
+ if(ctlr->base == 0)
+ return -1;
+ hp->port = ctlr->base;
+ hp->irq = ctlr->irq;
+ hp->aux = ctlr;
+
+ ctlr->r = vmap(ctlr->base, 0x1F0);
+ ctlr->opio = (Eopio *) ((uchar *) ctlr->r + 0x140);
+ ctlr->capio = (void *) ctlr->base;
+ hp->nports = 1;
+ ctlr->r[USBMODE] |= USBHOST;
+
+ ehcireset(ctlr);
+ ehcimeminit(ctlr);
+ ehcilinkage(hp);
+ ctlr->r[ULPI] = 1<<30 | 1<<29 | 0x0B << 16 | 3<<5;
+ if(hp->interrupt != nil)
+ intrenable(hp->irq, hp->interrupt, hp, LEVEL, hp->type);
+ return 0;
+}
+
+void
+usbehcilink(void)
+{
+ ehcidebug = 2;
+ addhcitype("ehci", reset);
+}
--- /dev/null
+++ b/sys/src/9/zynq/zynq
@@ -1,0 +1,56 @@
+dev
+ root
+ cons
+ arch
+ uart
+ mnt
+ srv
+ shr
+ proc
+ env
+ pipe
+ dup
+ ether netif
+ ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
+ ssl
+ tls
+ cap
+ kprof
+ fs
+ qspi
+ draw screen
+ mouse
+ usb
+
+link
+ etherzynq
+ ethermedium
+ loopbackmedium
+ usbehci usbehcizynq
+
+misc
+ uartzynq
+
+ip
+ tcp
+ udp
+ rudp
+ ipifc
+ icmp
+ icmp6
+ gre
+ ipmux
+ esp
+
+port
+ int cpuserver = 0;
+
+boot boot
+ tcp
+ local
+
+bootdir
+ boot$CONF.out boot
+ /$objtype/bin/paqfs
+ /$objtype/bin/auth/factotum
+ bootfs.paq
--- /dev/null
+++ b/sys/src/boot/zynq/boothead.c
@@ -1,0 +1,71 @@
+#include <u.h>
+#include <libc.h>
+
+char *data;
+uchar head[0x8c0];
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s file\n", argv0);
+ exits("usage");
+}
+
+void
+u32(int n, u32int p)
+{
+ head[n] = p;
+ head[n+1] = p >> 8;
+ head[n+2] = p >> 16;
+ head[n+3] = p >> 24;
+}
+
+u32int
+gu32(int n)
+{
+ return head[n] | head[n+1] << 8 | head[n+2] << 16 | head[n+3] << 24;
+}
+
+void
+main(int argc, char **argv)
+{
+ int fd, sz, i;
+ u32int ck;
+
+ ARGBEGIN {
+ default:
+ usage();
+ } ARGEND;
+
+ if(argc != 1)
+ usage();
+ fd = open(argv[0], OREAD);
+ if(fd < 0)
+ sysfatal("open: %r");
+ sz = seek(fd, 0, 2);
+ if(sz < 0)
+ sysfatal("seek: %r");
+ data = malloc(sz);
+ if(data == nil)
+ sysfatal("malloc: %r");
+ seek(fd, 0, 0);
+ if(readn(fd, data, sz) < sz)
+ sysfatal("read: %r");
+ close(fd);
+ memset(head, 0, sizeof(head));
+
+ u32(0x20, 0xaa995566);
+ u32(0x24, 0x584C4E58);
+ u32(0x30, sizeof(head));
+ u32(0x34, sz);
+ u32(0x40, sz);
+ ck = 0;
+ for(i = 0x20; i < 0x48; i += 4)
+ ck += gu32(i);
+ u32(0x48, ~ck);
+ u32(0xa0, -1);
+
+ write(1, head, sizeof(head));
+ write(1, data, sz);
+ exits(nil);
+}
--- /dev/null
+++ b/sys/src/boot/zynq/dat.h
@@ -1,0 +1,11 @@
+enum {
+ DHCPTIMEOUT = 2000,
+ ARPTIMEOUT = 1000,
+ TFTPTIMEOUT = 10000,
+
+ TZERO = 0x80000,
+ CONFSIZE = 65536,
+ CONF = TZERO - CONFSIZE,
+};
+
+#define nelem(x) (sizeof(x)/sizeof(*(x)))
--- /dev/null
+++ b/sys/src/boot/zynq/ddr.s
@@ -1,0 +1,258 @@
+#define OUTPUT_EN (3<<9)
+#define DCI_EN (7<<4)
+#define INP_VREF (1<<1)
+#define INP_DIFF (2<<1)
+
+TEXT ddriob(SB), $-4
+ WORD $(OUTPUT_EN) // DDRIOB_ADDR0
+ WORD $(OUTPUT_EN) // DDRIOB_ADDR1
+ WORD $(OUTPUT_EN | DCI_EN | INP_VREF) // DDRIOB_DATA0
+ WORD $(OUTPUT_EN | DCI_EN | INP_VREF) // DDRIOB_DATA1
+ WORD $(OUTPUT_EN | DCI_EN | INP_DIFF) // DDRIOB_DIFF0
+ WORD $(OUTPUT_EN | DCI_EN | INP_DIFF) // DDRIOB_DIFF1
+ WORD $(OUTPUT_EN) // DDRIOB_CLOCK
+ WORD $0x0018C61C // DDRIOB_DRIVE_SLEW_ADDR
+ WORD $0x00F9861C // DDRIOB_DRIVE_SLEW_DATA
+ WORD $0x00F9861C // DDRIOB_DRIVE_SLEW_DIFF
+ WORD $0x00F9861C // DDRIOB_DRIVE_SLEW_CLOCK
+ WORD $0xE60 // DDRIOB_DDR_CTRL
+
+TEXT ddrdata(SB), $-4
+ WORD $0XF8006000
+ WORD $0x0001FFFF
+ WORD $0x00000080
+ WORD $0XF8006004
+ WORD $0x1FFFFFFF
+ WORD $0x00081081
+ WORD $0XF8006008
+ WORD $0x03FFFFFF
+ WORD $0x03C0780F
+ WORD $0XF800600C
+ WORD $0x03FFFFFF
+ WORD $0x02001001
+ WORD $0XF8006010
+ WORD $0x03FFFFFF
+ WORD $0x00014001
+ WORD $0XF8006014
+ WORD $0x001FFFFF
+ WORD $0x0004281A
+ WORD $0XF8006018
+ WORD $0xF7FFFFFF
+ WORD $0x44E458D2
+ WORD $0XF800601C
+ WORD $0xFFFFFFFF
+ WORD $0x82023965
+ WORD $0XF8006020
+ WORD $0xFFFFFFFC
+ WORD $0x2B288290
+ WORD $0XF8006024
+ WORD $0x0FFFFFFF
+ WORD $0x0000003C
+ WORD $0XF8006028
+ WORD $0x00003FFF
+ WORD $0x00002007
+ WORD $0XF800602C
+ WORD $0xFFFFFFFF
+ WORD $0x00000008
+ WORD $0XF8006030
+ WORD $0xFFFFFFFF
+ WORD $0x00040970
+ WORD $0XF8006034
+ WORD $0x13FF3FFF
+ WORD $0x00011054
+ WORD $0XF8006038
+ WORD $0x00001FC3
+ WORD $0x00000000
+ WORD $0XF800603C
+ WORD $0x000FFFFF
+ WORD $0x00000777
+ WORD $0XF8006040
+ WORD $0xFFFFFFFF
+ WORD $0xFFF00000
+ WORD $0XF8006044
+ WORD $0x0FFFFFFF
+ WORD $0x0F666666
+ WORD $0XF8006048
+ WORD $0x3FFFFFFF
+ WORD $0x0003C248
+ WORD $0XF8006050
+ WORD $0xFF0F8FFF
+ WORD $0x77010800
+ WORD $0XF8006058
+ WORD $0x0001FFFF
+ WORD $0x00000101
+ WORD $0XF800605C
+ WORD $0x0000FFFF
+ WORD $0x00005003
+ WORD $0XF8006060
+ WORD $0x000017FF
+ WORD $0x0000003E
+ WORD $0XF8006064
+ WORD $0x00021FE0
+ WORD $0x00020000
+ WORD $0XF8006068
+ WORD $0x03FFFFFF
+ WORD $0x00284545
+ WORD $0XF800606C
+ WORD $0x0000FFFF
+ WORD $0x00001610
+ WORD $0XF80060A0
+ WORD $0x00FFFFFF
+ WORD $0x00008000
+ WORD $0XF80060A4
+ WORD $0xFFFFFFFF
+ WORD $0x10200802
+ WORD $0XF80060A8
+ WORD $0x0FFFFFFF
+ WORD $0x0690CB73
+ WORD $0XF80060AC
+ WORD $0x000001FF
+ WORD $0x000001FE
+ WORD $0XF80060B0
+ WORD $0x1FFFFFFF
+ WORD $0x04FFFFFF
+ WORD $0XF80060B4
+ WORD $0x000007FF
+ WORD $0x00000200
+ WORD $0XF80060B8
+ WORD $0x01FFFFFF
+ WORD $0x0020006A
+ WORD $0XF80060C4
+ WORD $0x00000003
+ WORD $0x00000003
+ WORD $0XF80060C4
+ WORD $0x00000003
+ WORD $0x00000000
+ WORD $0XF80060C8
+ WORD $0x000000FF
+ WORD $0x00000000
+ WORD $0XF80060DC
+ WORD $0x00000001
+ WORD $0x00000000
+ WORD $0XF80060F0
+ WORD $0x0000FFFF
+ WORD $0x00000000
+ WORD $0XF80060F4
+ WORD $0x0000000F
+ WORD $0x00000008
+ WORD $0XF8006114
+ WORD $0x000000FF
+ WORD $0x00000000
+ WORD $0XF8006118
+ WORD $0x7FFFFFFF
+ WORD $0x40000001
+ WORD $0XF800611C
+ WORD $0x7FFFFFFF
+ WORD $0x40000001
+ WORD $0XF8006120
+ WORD $0x7FFFFFFF
+ WORD $0x40000001
+ WORD $0XF8006124
+ WORD $0x7FFFFFFF
+ WORD $0x40000001
+ WORD $0XF800612C
+ WORD $0x000FFFFF
+ WORD $0x00000000
+ WORD $0XF8006130
+ WORD $0x000FFFFF
+ WORD $0x00000000
+ WORD $0XF8006134
+ WORD $0x000FFFFF
+ WORD $0x00000000
+ WORD $0XF8006138
+ WORD $0x000FFFFF
+ WORD $0x00000000
+ WORD $0XF8006140
+ WORD $0x000FFFFF
+ WORD $0x00000035
+ WORD $0XF8006144
+ WORD $0x000FFFFF
+ WORD $0x00000035
+ WORD $0XF8006148
+ WORD $0x000FFFFF
+ WORD $0x00000035
+ WORD $0XF800614C
+ WORD $0x000FFFFF
+ WORD $0x00000035
+ WORD $0XF8006154
+ WORD $0x000FFFFF
+ WORD $0x00000080
+ WORD $0XF8006158
+ WORD $0x000FFFFF
+ WORD $0x00000080
+ WORD $0XF800615C
+ WORD $0x000FFFFF
+ WORD $0x00000080
+ WORD $0XF8006160
+ WORD $0x000FFFFF
+ WORD $0x00000075
+ WORD $0XF8006168
+ WORD $0x001FFFFF
+ WORD $0x000000EE
+ WORD $0XF800616C
+ WORD $0x001FFFFF
+ WORD $0x000000E4
+ WORD $0XF8006170
+ WORD $0x001FFFFF
+ WORD $0x000000FC
+ WORD $0XF8006174
+ WORD $0x001FFFFF
+ WORD $0x000000F4
+ WORD $0XF800617C
+ WORD $0x000FFFFF
+ WORD $0x000000C0
+ WORD $0XF8006180
+ WORD $0x000FFFFF
+ WORD $0x000000C0
+ WORD $0XF8006184
+ WORD $0x000FFFFF
+ WORD $0x000000C0
+ WORD $0XF8006188
+ WORD $0x000FFFFF
+ WORD $0x000000B5
+ WORD $0XF8006190
+ WORD $0xFFFFFFFF
+ WORD $0x10040080
+ WORD $0XF8006194
+ WORD $0x000FFFFF
+ WORD $0x00007D02
+ WORD $0XF8006204
+ WORD $0xFFFFFFFF
+ WORD $0x00000000
+ WORD $0XF8006208
+ WORD $0x000F03FF
+ WORD $0x000803FF
+ WORD $0XF800620C
+ WORD $0x000F03FF
+ WORD $0x000803FF
+ WORD $0XF8006210
+ WORD $0x000F03FF
+ WORD $0x000803FF
+ WORD $0XF8006214
+ WORD $0x000F03FF
+ WORD $0x000803FF
+ WORD $0XF8006218
+ WORD $0x000F03FF
+ WORD $0x000003FF
+ WORD $0XF800621C
+ WORD $0x000F03FF
+ WORD $0x000003FF
+ WORD $0XF8006220
+ WORD $0x000F03FF
+ WORD $0x000003FF
+ WORD $0XF8006224
+ WORD $0x000F03FF
+ WORD $0x000003FF
+ WORD $0XF80062A8
+ WORD $0x00000FF7
+ WORD $0x00000000
+ WORD $0XF80062AC
+ WORD $0xFFFFFFFF
+ WORD $0x00000000
+ WORD $0XF80062B0
+ WORD $0x003FFFFF
+ WORD $0x00005125
+ WORD $0xF80062B4
+ WORD $0x003FFFFF
+ WORD $0x000012A8
+ WORD $0
--- /dev/null
+++ b/sys/src/boot/zynq/fns.h
@@ -1,0 +1,13 @@
+void putc(int);
+void puts(char *);
+int netboot(void);
+void puthex(u32int);
+void memset(void *, char, int);
+void memcpy(void *, void *, int);
+void print(char *, ...);
+u32int u32get(void *);
+void jump(void *);
+void sleep(int);
+void timeren(int);
+int timertrig(void);
+void flash(void);
--- /dev/null
+++ b/sys/src/boot/zynq/fsbl.s
@@ -1,0 +1,310 @@
+#include "mem.h"
+
+#define Rb R10
+#define SET(R, V) MOVW $(V), R0 ; MOVW R0, (R)(Rb)
+#define RMW(r, m, v) MOVW (r)(Rb), R0; BIC $(m), R0; ORR $(v), R0; MOVW R0, (r)(Rb)
+
+TEXT _start(SB), $-4
+ WORD $0xea000006
+ MOVW $abort(SB), R15
+ MOVW $abort(SB), R15
+ MOVW $abort(SB), R15
+ MOVW $abort(SB), R15
+ MOVW $abort(SB), R15
+ MOVW $abort(SB), R15
+ MOVW $abort(SB), R15
+
+TEXT reloc(SB), $-4
+ MOVW $(1<<7|1<<6|0x13), R0
+ MOVW R0, CPSR
+ MOVW $STACKTOP, R13
+ MOVW $_start(SB), R0
+ MCR CpMMU, 0, R0, C(12), C(0)
+ MOVW $SLCR_BASE, Rb
+ SET(SLCR_UNLOCK, UNLOCK_KEY)
+ MOVW $0, R0
+ MCR 15, 0, R0, C(8), C(7), 0
+ MCR 15, 0, R0, C(7), C(5), 0
+ MCR 15, 0, R0, C(7), C(5), 6
+ MOVW $0xc5047a, R1
+ MCR 15, 0, R1, C(1), C(0), 0
+ DSB
+ ISB
+ CMP.S $0, R15
+ BL.LT reset(SB)
+
+ MOVW $0xf, R1
+ MOVW $0xffff0000, R3
+ MOVW $0xe58a1910, R0
+ MOVW R0, (R3)
+ MOVW $0xf57ff04f, R0
+ MOVW R0, 4(R3)
+ MOVW $0xf57ff06f, R0
+ MOVW R0, 8(R3)
+ MOVW $0xe28ef000, R0
+ MOVW R0, 12(R3)
+ MOVW $reset(SB), R14
+ DSB
+ ISB
+ MOVW R3, R15
+
+TEXT reset(SB), $-4
+ BL pllsetup(SB)
+ BL miosetup(SB)
+ BL ddrsetup(SB)
+ BL uartsetup(SB)
+ MOVW $SLCR_BASE, Rb
+ SET(SLCR_LOCK, LOCK_KEY)
+// BL memtest(SB)
+ MOVW $setR12(SB), R12
+ BL main(SB)
+ B abort(SB)
+
+TEXT pllsetup(SB), $0
+ MOVW $SLCR_BASE, Rb
+
+ SET(ARM_PLL_CFG, ARM_PLL_CFG_VAL)
+ SET(DDR_PLL_CFG, DDR_PLL_CFG_VAL)
+ SET(IO_PLL_CFG, IO_PLL_CFG_VAL)
+
+ MOVW $(ARM_FDIV | PLL_BYPASS_FORCE), R0
+ MOVW R0, ARM_PLL_CTRL(Rb)
+ ORR $(PLL_RESET), R4
+ MOVW R4, ARM_PLL_CTRL(Rb)
+ MOVW R0, ARM_PLL_CTRL(Rb)
+
+ MOVW $(DDR_FDIV | PLL_BYPASS_FORCE), R0
+ MOVW R0, DDR_PLL_CTRL(Rb)
+ ORR $(PLL_RESET), R4
+ MOVW R4, DDR_PLL_CTRL(Rb)
+ MOVW R0, DDR_PLL_CTRL(Rb)
+
+ MOVW $(IO_FDIV | PLL_BYPASS_FORCE), R0
+ MOVW R0, IO_PLL_CTRL(Rb)
+ ORR $(PLL_RESET), R4
+ MOVW R4, IO_PLL_CTRL(Rb)
+ MOVW R0, IO_PLL_CTRL(Rb)
+
+_pllsetupl:
+ MOVW PLL_STATUS(Rb), R0
+ AND $7, R0
+ CMP.S $7, R0
+ BNE _pllsetupl
+
+ SET(ARM_PLL_CTRL, ARM_FDIV)
+ SET(DDR_PLL_CTRL, DDR_FDIV)
+ SET(IO_PLL_CTRL, IO_FDIV)
+
+ SET(ARM_CLK_CTRL, 0x1f << 24 | CPU_DIV << 8)
+ SET(UART_CLK_CTRL, UART_DIV << 8 | 3)
+ SET(DDR_CLK_CTRL, DDR_DIV3 << 20 | DDR_DIV2 << 26 | 3)
+ SET(DCI_CLK_CTRL, DCI_DIV0 << 8 | DCI_DIV1 << 20 | 1)
+ SET(GEM0_RCLK_CTRL, 1)
+ SET(GEM1_RCLK_CTRL, 0)
+ SET(GEM0_CLK_CTRL, ETH_DIV0 << 8 | ETH_DIV1 << 20 | 1)
+ SET(GEM1_CLK_CTRL, 0)
+ SET(GPIOB_CTRL, VREF_SW_EN)
+ SET(APER_CLK_CTRL, LQSPI_CLK_EN | GPIO_CLK_EN | UART0_CLK_EN | UART1_CLK_EN | I2C0_CLK_EN | SDIO1_CLK_EN | GEM0_CLK_EN | USB0_CLK_EN | USB1_CLK_EN | DMA_CLK_EN)
+ SET(SMC_CLK_CTRL, 0x3C20)
+ SET(LQSPI_CLK_CTRL, QSPI_DIV << 8 | 1)
+ SET(SDIO_CLK_CTRL, SDIO_DIV << 8 | 2)
+ SET(SPI_CLK_CTRL, 0x3F00)
+ SET(CAN_CLK_CTRL, 0x501900)
+ SET(PCAP_CLK_CTRL, PCAP_DIV << 8 | 1)
+ RET
+
+TEXT miosetup(SB), $0
+ MOVW $SLCR_BASE, Rb
+ SET(UART_RST_CTRL, 0xf)
+ SET(UART_RST_CTRL, 0)
+
+ MOVW $miodata(SB), R1
+ ADD $MIO_PIN_0, Rb, R2
+ MOVW $54, R3
+ BL copy(SB)
+
+ MOVW $0, R0
+ MOVW R0, MIO_MST_TRI0(Rb)
+ MOVW R0, MIO_MST_TRI1(Rb)
+ RET
+
+TEXT copy(SB), $0
+_copyl:
+ MOVW.P 4(R1), R0
+ MOVW.P R0, 4(R2)
+ SUB.S $1, R3
+ BNE _copyl
+ RET
+
+TEXT ddrsetup(SB), $0
+ MOVW $SLCR_BASE, Rb
+ RMW(DDRIOB_DCI_CTRL, DCI_RESET, DCI_RESET)
+ RMW(DDRIOB_DCI_CTRL, DCI_RESET, 0)
+ RMW(DDRIOB_DCI_CTRL, DDRIOB_DCI_CTRL_MASK, DCI_NREF | DCI_ENABLE | DCI_RESET)
+
+ MOVW $ddriob(SB), R1
+ ADD $DDRIOB_ADDR0, Rb, R2
+ MOVW $12, R3
+ BL copy(SB)
+
+ MOVW $ddrdata(SB), R1
+_ddrl1:
+ MOVW.P 4(R1), R2
+ ORR.S $0, R2
+ BEQ _ddrl2
+ MOVW.P 4(R1), R3
+ MOVW.P 4(R1), R4
+ AND R3, R4
+ MOVW (R2), R0
+ BIC R3, R0
+ ORR R4, R0
+ MOVW R0, (R2)
+ B _ddrl1
+_ddrl2:
+ MOVW DDRIOB_DCI_STATUS(Rb), R0
+ AND.S $(1<<13), R0
+ BEQ _ddrl2
+ MOVW $DDR_BASE, Rb
+ RMW(DDRC_CTRL, 0x1ffff, 0x81)
+_ddrl4:
+ MOVW DDR_MODE_STS(Rb), R0
+ AND.S $7, R0
+ BEQ _ddrl4
+
+ MOVW $MP_BASE, Rb
+ SET(FILTER_START, 0)
+ RET
+
+TEXT memtest(SB), $0
+ MOVW $0, R0
+ ADD $(1024 * 1024 * 10), R0, R1
+_testl:
+ MOVW R0, (R0)
+ ADD $4, R0
+ CMP.S R0, R1
+ BNE _testl
+ MOVW $0, R0
+_testl2:
+ MOVW (R0), R2
+ CMP.S R0, R2
+ BNE _no
+ ADD $4, R0
+ CMP.S R0, R1
+ BNE _testl2
+ MOVW $'.', R0
+ BL putc(SB)
+ RET
+_no:
+ MOVW $'!', R0
+ BL putc(SB)
+ RET
+
+TEXT uartsetup(SB), $0
+ MOVW $UART1_BASE, Rb
+ SET(UART_CTRL, 0x17)
+ SET(UART_MODE, 0x20)
+ SET(UART_SAMP, 15)
+ SET(UART_BAUD, 14)
+ RET
+
+TEXT putc(SB), $0
+ MOVW $UART1_BASE, Rb
+ CMP.S $10, R0
+ BNE _putcl
+ MOVW R0, R2
+ MOVW $13, R0
+ BL putc(SB)
+ MOVW R2, R0
+_putcl:
+ MOVW UART_STAT(Rb), R1
+ AND.S $0x10, R1
+ BNE _putcl
+ AND $0xFF, R0
+ MOVW R0, UART_DATA(Rb)
+ RET
+
+TEXT jump(SB), $-4
+ MOVW R0, R15
+
+TEXT abort(SB), $0
+ MOVW $'?', R0
+ BL putc(SB)
+_loop:
+ WFE
+ B _loop
+
+#define TRI 1
+#define LVCMOS18 (1<<9)
+#define LVCMOS25 (2<<9)
+#define LVCMOS33 (3<<9)
+#define HSTL (4<<9)
+#define PULLUP (1<<12)
+#define NORECV (1<<13)
+#define FAST (1<<8)
+#define MUX(a, b, c, d) ((a)<<1 | (b)<<2 | (c)<<3 | (d)<<5)
+
+#define NO (TRI | LVCMOS33)
+#define SPI (MUX(1, 0, 0, 0) | LVCMOS33)
+#define UART (MUX(0, 0, 0, 7) | LVCMOS33)
+#define SD (MUX(0, 0, 0, 4) | LVCMOS33)
+#define ETX (MUX(1, 0, 0, 0) | HSTL | NORECV | PULLUP)
+#define ERX (MUX(1, 0, 0, 0) | HSTL | TRI | PULLUP)
+#define USB (MUX(0, 1, 0, 0) | LVCMOS18)
+#define MDCLK (MUX(0, 0, 0, 4) | HSTL)
+#define MDDATA (MUX(0, 0, 0, 4) | HSTL)
+
+TEXT miodata(SB), $-4
+ WORD $NO // 0
+ WORD $SPI // 1
+ WORD $SPI // 2
+ WORD $SPI // 3
+ WORD $SPI // 4
+ WORD $SPI // 5
+ WORD $SPI // 6
+ WORD $NO // 7
+ WORD $UART // 8
+ WORD $(UART|TRI) // 9
+ WORD $SD // 10
+ WORD $SD // 11
+ WORD $SD // 12
+ WORD $SD // 13
+ WORD $SD // 14
+ WORD $SD // 15
+ WORD $ETX // 16
+ WORD $ETX // 17
+ WORD $ETX // 18
+ WORD $ETX // 19
+ WORD $ETX // 20
+ WORD $ETX // 21
+ WORD $ERX // 22
+ WORD $ERX // 23
+ WORD $ERX // 24
+ WORD $ERX // 25
+ WORD $ERX // 26
+ WORD $ERX // 27
+ WORD $USB // 28
+ WORD $USB // 29
+ WORD $USB // 30
+ WORD $USB // 31
+ WORD $USB // 32
+ WORD $USB // 33
+ WORD $USB // 34
+ WORD $USB // 35
+ WORD $USB // 36
+ WORD $USB // 37
+ WORD $USB // 38
+ WORD $USB // 39
+ WORD $USB // 40
+ WORD $USB // 41
+ WORD $USB // 42
+ WORD $USB // 43
+ WORD $USB // 44
+ WORD $USB // 45
+ WORD $USB // 46
+ WORD $USB // 47
+ WORD $USB // 48
+ WORD $USB // 49
+ WORD $USB // 50
+ WORD $USB // 51
+ WORD $MDCLK // 52
+ WORD $MDDATA // 53
--- /dev/null
+++ b/sys/src/boot/zynq/main.c
@@ -1,0 +1,184 @@
+#include <u.h>
+#include <a.out.h>
+#include "dat.h"
+#include "fns.h"
+
+void
+puts(char *s)
+{
+ while(*s)
+ putc(*s++);
+}
+
+void
+puthex(u32int u)
+{
+ static char *dig = "0123456789abcdef";
+ int i;
+
+ for(i = 0; i < 8; i++){
+ putc(dig[u >> 28]);
+ u <<= 4;
+ }
+}
+
+void
+putdec(int n)
+{
+ if(n / 10 != 0)
+ putdec(n / 10);
+ putc(n % 10 + '0');
+}
+
+void
+print(char *s, ...)
+{
+ va_list va;
+ int n;
+ u32int u;
+
+ va_start(va, s);
+ while(*s)
+ if(*s == '%'){
+ switch(*++s){
+ case 's':
+ puts(va_arg(va, char *));
+ break;
+ case 'x':
+ puthex(va_arg(va, u32int));
+ break;
+ case 'd':
+ n = va_arg(va, int);
+ if(n < 0){
+ putc('-');
+ putdec(-n);
+ }else
+ putdec(n);
+ break;
+ case 'I':
+ u = va_arg(va, u32int);
+ putdec(u >> 24);
+ putc('.');
+ putdec((uchar)(u >> 16));
+ putc('.');
+ putdec((uchar)(u >> 8));
+ putc('.');
+ putdec((uchar)u);
+ break;
+ case 0:
+ va_end(va);
+ return;
+ }
+ s++;
+ }else
+ putc(*s++);
+ va_end(va);
+}
+
+void
+memset(void *v, char c, int n)
+{
+ char *vc;
+
+ vc = v;
+ while(n--)
+ *vc++ = c;
+}
+
+void
+memcpy(void *d, void *s, int n)
+{
+ char *cd, *cs;
+
+ cd = d;
+ cs = s;
+ while(n--)
+ *cd++ = *cs++;
+}
+
+void
+run(void)
+{
+ ulong t, tr;
+ char *p, *d;
+ int n;
+ ulong *h;
+
+ h = (ulong *) TZERO;
+ if(u32get(&h[0]) != E_MAGIC){
+ print("invalid magic: %x != %x\n", u32get(&h[0]), E_MAGIC);
+ return;
+ }
+ t = u32get(&h[1]) + 0x20;
+ tr = t + 0xfff & ~0xfff;
+ if(t != tr){
+ n = u32get(&h[2]);
+ p = (char *) (TZERO + t + n);
+ d = (char *) (TZERO + tr + n);
+ while(n--)
+ *--d = *--p;
+ }
+ p = (char *) (TZERO + tr + u32get(&h[2]));
+ memset(p, 0, u32get(&h[3]));
+ jump((void *) (u32get(&h[5]) & 0xfffffff));
+}
+
+enum {
+ TIMERVALL,
+ TIMERVALH,
+ TIMERCTL,
+ TIMERSTAT,
+ TIMERCOMPL,
+ TIMERCOMPH,
+};
+
+void
+timeren(int n)
+{
+ ulong *r;
+
+ r = (ulong *) 0xf8f00200;
+ if(n < 0){
+ r[TIMERSTAT] |= 1;
+ r[TIMERCTL] = 0;
+ return;
+ }
+ r[TIMERCTL] = 0;
+ r[TIMERVALL] = 0;
+ r[TIMERVALH] = 0;
+ r[TIMERCOMPL] = 1000 * n;
+ r[TIMERCOMPH] = 0;
+ r[TIMERSTAT] |= 1;
+ r[TIMERCTL] = 100 << 8 | 3;
+}
+
+int
+timertrig(void)
+{
+ ulong *r;
+
+ r = (ulong *) 0xf8f00200;
+ if((r[TIMERSTAT] & 1) != 0){
+ r[TIMERCTL] = 0;
+ r[TIMERSTAT] |= 1;
+ return 1;
+ }
+ return 0;
+}
+
+void
+sleep(int n)
+{
+ timeren(n);
+ while(!timertrig())
+ ;
+}
+
+void
+main(void)
+{
+ puts("Booting ...\n");
+ if(netboot() > 0)
+ run();
+ print("hjboot: ending\n");
+}
--- /dev/null
+++ b/sys/src/boot/zynq/mem.h
@@ -1,0 +1,107 @@
+#define STACKTOP 0xFFFFFE00
+
+#define ARM_FDIV (40 << PLL_FDIV_SH)
+#define DDR_FDIV (32 << PLL_FDIV_SH)
+#define IO_FDIV (30 << PLL_FDIV_SH)
+#define PLL_CFG_VAL(CP, RES, CNT) ((CP)<<8 | (RES)<<4 | (CNT)<<12)
+#define ARM_PLL_CFG_VAL PLL_CFG_VAL(2, 2, 250)
+#define DDR_PLL_CFG_VAL PLL_CFG_VAL(2, 2, 300)
+#define IO_PLL_CFG_VAL PLL_CFG_VAL(2, 12, 325)
+#define PLL_FDIV_SH 12
+#define PLL_BYPASS_FORCE 0x10
+#define PLL_RESET 0x01
+
+#define CPU_DIV 2
+#define DDR_DIV3 2
+#define DDR_DIV2 3
+#define UART_DIV 40
+#define DCI_DIV0 20
+#define DCI_DIV1 5
+#define ETH_DIV0 8
+#define ETH_DIV1 1
+#define QSPI_DIV 5
+#define SDIO_DIV 10
+#define PCAP_DIV 5
+#define MDC_DIV 6 /* this value depends on CPU_1xCLK, see TRM GEM.net_cfg description */
+
+#define SLCR_BASE 0xF8000000
+#define SLCR_LOCK 0x004
+#define LOCK_KEY 0x767B
+#define SLCR_UNLOCK 0x008
+#define UNLOCK_KEY 0xDF0D
+
+#define ARM_PLL_CTRL 0x100
+#define DDR_PLL_CTRL 0x104
+#define IO_PLL_CTRL 0x108
+#define PLL_STATUS 0x10C
+#define ARM_PLL_CFG 0x110
+#define DDR_PLL_CFG 0x114
+#define IO_PLL_CFG 0x118
+#define ARM_CLK_CTRL 0x120
+#define DDR_CLK_CTRL 0x124
+#define DCI_CLK_CTRL 0x128
+#define APER_CLK_CTRL 0x12C
+#define GEM0_RCLK_CTRL 0x138
+#define GEM1_RCLK_CTRL 0x13C
+#define GEM0_CLK_CTRL 0x140
+#define GEM1_CLK_CTRL 0x144
+#define SMC_CLK_CTRL 0x148
+#define LQSPI_CLK_CTRL 0x14C
+#define SDIO_CLK_CTRL 0x150
+#define UART_CLK_CTRL 0x154
+#define SPI_CLK_CTRL 0x158
+#define CAN_CLK_CTRL 0x15C
+#define PCAP_CLK_CTRL 0x168
+#define UART_RST_CTRL 0x228
+#define A9_CPU_RST_CTRL 0x244
+
+#define LQSPI_CLK_EN (1<<23)
+#define GPIO_CLK_EN (1<<22)
+#define UART0_CLK_EN (1<<20)
+#define UART1_CLK_EN (1<<21)
+#define I2C0_CLK_EN (1<<18)
+#define SDIO1_CLK_EN (1<<11)
+#define GEM0_CLK_EN (1<<6)
+#define USB1_CLK_EN (1<<3)
+#define USB0_CLK_EN (1<<2)
+#define DMA_CLK_EN (1<<0)
+
+#define MIO_PIN_0 0x00000700
+#define MIO_MST_TRI0 0x80C
+#define MIO_MST_TRI1 0x810
+#define OCM_CFG 0x910
+#define GPIOB_CTRL 0xB00
+#define VREF_SW_EN (1<<11)
+#define DDRIOB_ADDR0 0xB40
+#define DDRIOB_DCI_CTRL 0xB70
+#define DDRIOB_DCI_CTRL_MASK 0x1ffc3
+#define DDRIOB_DCI_STATUS 0xB74
+#define DCI_RESET 1
+#define DCI_NREF (1<<11)
+#define DCI_ENABLE 2
+
+#define DDR_BASE 0xF8006000
+#define DDRC_CTRL 0x0
+#define DDR_MODE_STS 0x54
+
+#define UART1_BASE 0xE0001000
+#define UART_CTRL 0x0
+#define UART_MODE 0x4
+#define UART_BAUD 0x18
+#define UART_STAT 0x2C
+#define UART_DATA 0x30
+#define UART_SAMP 0x34
+
+#define QSPI_BASE 0xE000D000
+#define QSPI_CFG 0x0
+#define SPI_EN 0x4
+#define QSPI_TX 0x1c
+
+#define MP_BASE 0xF8F00000
+#define FILTER_START 0x40
+
+#define CpMMU 15
+
+#define DSB WORD $0xf57ff04f
+#define ISB WORD $0xf57ff06f
+#define WFE WORD $0xe320f002
--- /dev/null
+++ b/sys/src/boot/zynq/mkfile
@@ -1,0 +1,34 @@
+objtype=arm
+</$objtype/mkfile
+BIN=/arm
+TARG=fsbl fsbl.img
+CLEANFILES=boothead.$cputype
+FSBLFILES=fsbl.$O ddr.$O main.$O net.$O div.$O qspi.$O
+
+all:V: $TARG
+
+clean:V:
+ rm -rf $TARG *.$O
+
+fsbl: $FSBLFILES
+ $LD -o $target -T0xfffc0000 -H6 -R4096 -l -s $prereq
+
+9fsbl: $FSBLFILES
+ $LD -o $target -T0xfffc0000 -l $prereq
+
+fsbl.img:D: fsbl boothead.$cputype
+ boothead.$cputype fsbl >fsbl.img
+
+boothead.$cputype:V: mkfile.boothead
+ @{objtype=$cputype mk -f $prereq all}
+
+div.$O: /sys/src/libc/arm/div.s
+ $AS /sys/src/libc/arm/div.s
+
+%.$O: dat.h fns.h mem.h
+
+%.$O: %.s
+ $AS $stem.s
+
+%.$O: %.c
+ $CC $CFLAGS $stem.c
--- /dev/null
+++ b/sys/src/boot/zynq/mkfile.boothead
@@ -1,0 +1,9 @@
+</$objtype/mkfile
+
+all:V: boothead.$objtype
+
+boothead.$objtype: boothead.$O
+ $LD $LDFLAGS -o $target $prereq
+
+%.$O: %.c
+ $CC $CFLAGS $stem.c
--- /dev/null
+++ b/sys/src/boot/zynq/net.c
@@ -1,0 +1,591 @@
+#include <u.h>
+#include "dat.h"
+#include "fns.h"
+#include "mem.h"
+
+enum {
+ ETHLEN = 1600,
+ UDPLEN = 576,
+ NRX = 64,
+ RXBASE = 128 * 1024 * 1024,
+
+ ETHHEAD = 14,
+ IPHEAD = 20,
+ UDPHEAD = 8,
+
+ BOOTREQ = 1,
+ DHCPDISCOVER = 1,
+ DHCPOFFER,
+ DHCPREQUEST,
+ DHCPDECLINE,
+};
+
+enum {
+ NET_CTRL,
+ NET_CFG,
+ NET_STATUS,
+ DMA_CFG = 4,
+ TX_STATUS,
+ RX_QBAR,
+ TX_QBAR,
+ RX_STATUS,
+ INTR_STATUS,
+ INTR_EN,
+ INTR_DIS,
+ INTR_MASK,
+ PHY_MAINT,
+ RX_PAUSEQ,
+ TX_PAUSEQ,
+ HASH_BOT = 32,
+ HASH_TOP,
+ SPEC_ADDR1_BOT,
+ SPEC_ADDR1_TOP,
+};
+
+enum {
+ MDCTRL,
+ MDSTATUS,
+ MDID1,
+ MDID2,
+ MDAUTOADV,
+ MDAUTOPART,
+ MDAUTOEX,
+ MDAUTONEXT,
+ MDAUTOLINK,
+ MDGCTRL,
+ MDGSTATUS,
+ MDPHYCTRL = 0x1f,
+};
+
+enum {
+ /* NET_CTRL */
+ RXEN = 1<<2,
+ TXEN = 1<<3,
+ MDEN = 1<<4,
+ STARTTX = 1<<9,
+ /* NET_CFG */
+ SPEED = 1<<0,
+ FDEN = 1<<1,
+ RX1536EN = 1<<8,
+ GIGE_EN = 1<<10,
+ RXCHKSUMEN = 1<<24,
+ /* NET_STATUS */
+ PHY_IDLE = 1<<2,
+ /* DMA_CFG */
+ TXCHKSUMEN = 1<<11,
+ /* TX_STATUS */
+ TXCOMPL = 1<<5,
+ /* MDCTRL */
+ MDRESET = 1<<15,
+ AUTONEG = 1<<12,
+ FULLDUP = 1<<8,
+ /* MDSTATUS */
+ LINK = 1<<2,
+ /* MDGSTATUS */
+ RECVOK = 3<<12,
+};
+
+typedef struct {
+ uchar edest[6];
+ uchar esrc[6];
+ ulong idest;
+ ulong isrc;
+ ushort dport, sport;
+ ushort len;
+ uchar data[UDPLEN];
+} udp;
+
+static ulong *eth0 = (ulong *) 0xe000b000;
+static int phyaddr = 7;
+
+static u32int myip, dhcpip, tftpip, xid;
+static uchar mac[6] = {0x0E, 0xA7, 0xDE, 0xAD, 0xBE, 0xEF};
+static uchar tmac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+static char file[128];
+
+static udp ubuf, urbuf;
+static uchar txbuf[ETHLEN];
+static ulong txdesc[4], *txact, *rxact;
+static ulong rxdesc[NRX*2];
+
+void
+mdwrite(ulong *r, int reg, u16int val)
+{
+ while((r[NET_STATUS] & PHY_IDLE) == 0)
+ ;
+ r[PHY_MAINT] = 1<<30 | 1<<28 | 1<<17 | phyaddr << 23 | reg << 18 | val;
+ while((r[NET_STATUS] & PHY_IDLE) == 0)
+ ;
+}
+
+u16int
+mdread(ulong *r, int reg)
+{
+ while((r[NET_STATUS] & PHY_IDLE) == 0)
+ ;
+ r[PHY_MAINT] = 1<<30 | 1<<29 | 1<<17 | phyaddr << 23 | reg << 18;
+ while((r[NET_STATUS] & PHY_IDLE) == 0)
+ ;
+ return r[PHY_MAINT];
+}
+
+void
+ethinit(ulong *r)
+{
+ int v;
+ ulong *p;
+ ulong d;
+
+ r[NET_CTRL] = 0;
+ r[RX_STATUS] = 0xf;
+ r[TX_STATUS] = 0xff;
+ r[INTR_DIS] = 0x7FFFEFF;
+ r[RX_QBAR] = r[TX_QBAR] = 0;
+ r[NET_CFG] = MDC_DIV << 18 | FDEN | SPEED | RX1536EN | GIGE_EN | RXCHKSUMEN;
+ r[SPEC_ADDR1_BOT] = mac[0] | mac[1] << 8 | mac[2] << 16 | mac[3] << 24;
+ r[SPEC_ADDR1_TOP] = mac[4] | mac[5] << 8;
+ r[DMA_CFG] = TXCHKSUMEN | 0x18 << 16 | 1 << 10 | 3 << 8 | 0x10;
+
+ txdesc[0] = 0;
+ txdesc[1] = 1<<31;
+ txdesc[2] = 0;
+ txdesc[3] = 1<<31 | 1<<30;
+ txact = txdesc;
+ r[TX_QBAR] = (ulong) txdesc;
+ for(p = rxdesc, d = RXBASE; p < rxdesc + nelem(rxdesc); d += ETHLEN){
+ *p++ = d;
+ *p++ = 0;
+ }
+ p[-2] |= 2;
+ rxact = rxdesc;
+ r[RX_QBAR] = (ulong) rxdesc;
+
+ r[NET_CTRL] = MDEN;
+// mdwrite(r, MDCTRL, MDRESET);
+ mdwrite(r, MDCTRL, AUTONEG);
+ if((mdread(r, MDSTATUS) & LINK) == 0){
+ puts("Waiting for Link ...\n");
+ while((mdread(r, MDSTATUS) & LINK) == 0)
+ ;
+ }
+ v = mdread(r, MDPHYCTRL);
+ if((v & 0x40) != 0){
+ puts("1000BASE-T");
+ while((mdread(r, MDGSTATUS) & RECVOK) != RECVOK)
+ ;
+ r[NET_CFG] |= GIGE_EN;
+ }else if((v & 0x20) != 0){
+ puts("100BASE-TX");
+ r[NET_CFG] = NET_CFG & ~GIGE_EN | SPEED;
+ }else if((v & 0x10) != 0){
+ puts("10BASE-T");
+ r[NET_CFG] = NET_CFG & ~(GIGE_EN | SPEED);
+ }else
+ puts("???");
+ if((v & 0x08) != 0)
+ puts(" Full Duplex\n");
+ else{
+ puts(" Half Duplex\n");
+ r[NET_CFG] &= ~FDEN;
+ }
+ r[NET_CTRL] |= TXEN | RXEN;
+}
+
+u32int
+u32get(void *pp)
+{
+ uchar *p;
+
+ p = pp;
+ return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
+}
+
+uchar *
+u32put(uchar *p, u32int v)
+{
+ p[0] = v >> 24;
+ p[1] = v >> 16;
+ p[2] = v >> 8;
+ p[3] = v;
+ return p + 4;
+}
+
+void
+ethtx(ulong *r, uchar *buf, int len)
+{
+ txact[0] = (ulong) buf;
+ txact[1] = 1<<15 | len;
+ if(txact == txdesc + nelem(txdesc) - 2){
+ txact[1] |= 1<<30;
+ txact = txdesc;
+ }else
+ txact += 2;
+ r[TX_STATUS] = -1;
+ r[NET_CTRL] |= STARTTX;
+ while((r[TX_STATUS] & TXCOMPL) == 0)
+ ;
+}
+
+void
+udptx(ulong *r, udp *u)
+{
+ uchar *p, *q;
+ int n;
+
+ p = q = txbuf;
+ memcpy(p, u->edest, 6);
+ memcpy(p + 6, u->esrc, 6);
+ q += 12;
+ *q++ = 8;
+ *q++ = 0;
+
+ *q++ = 5 | 4 << 4;
+ *q++ = 0;
+ n = IPHEAD + UDPHEAD + u->len;
+ *q++ = n >> 8;
+ *q++ = n;
+
+ *q++ = 0x13;
+ *q++ = 0x37;
+ *q++ = 1<<6;
+ *q++ = 0;
+
+ *q++ = 1;
+ *q++ = 0x11;
+ *q++ = 0;
+ *q++ = 0;
+ q = u32put(q, u->isrc);
+ q = u32put(q, u->idest);
+
+ *q++ = u->sport >> 8;
+ *q++ = u->sport;
+ *q++ = u->dport >> 8;
+ *q++ = u->dport;
+ n = UDPHEAD + u->len;
+ *q++ = n >> 8;
+ *q++ = n;
+ *q++ = 0;
+ *q++ = 0;
+
+ memcpy(q, u->data, u->len);
+ ethtx(r, p, ETHHEAD + IPHEAD + UDPHEAD + u->len);
+}
+
+void
+dhcppkg(ulong *r, int t)
+{
+ uchar *p;
+ udp *u;
+
+ u = &ubuf;
+ p = u->data;
+ *p++ = BOOTREQ;
+ *p++ = 1;
+ *p++ = 6;
+ *p++ = 0;
+ p = u32put(p, xid);
+ p = u32put(p, 0x8000);
+ memset(p, 0, 16);
+ u32put(p + 8, dhcpip);
+ p += 16;
+ memcpy(p, mac, 6);
+ p += 6;
+ memset(p, 0, 202);
+ p += 202;
+ *p++ = 99;
+ *p++ = 130;
+ *p++ = 83;
+ *p++ = 99;
+
+ *p++ = 53;
+ *p++ = 1;
+ *p++ = t;
+ if(t == DHCPREQUEST){
+ *p++ = 50;
+ *p++ = 4;
+ p = u32put(p, myip);
+ *p++ = 54;
+ *p++ = 4;
+ p = u32put(p, dhcpip);
+ }
+
+ *p++ = 0xff;
+
+ memset(u->edest, 0xff, 6);
+ memcpy(u->esrc, mac, 6);
+ u->sport = 68;
+ u->dport = 67;
+ u->idest = -1;
+ u->isrc = 0;
+ u->len = p - u->data;
+ udptx(r, u);
+}
+
+uchar *
+ethrx(void)
+{
+ while((*rxact & 1) == 0)
+ if(timertrig())
+ return nil;
+ return (uchar *) (*rxact & ~3);
+}
+
+void
+ethnext(void)
+{
+ *rxact &= ~1;
+ if((*rxact & 2) != 0)
+ rxact = rxdesc;
+ else
+ rxact += 2;
+}
+
+void
+arp(int op, uchar *edest, ulong idest)
+{
+ uchar *p;
+ static uchar broad[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ p = txbuf;
+ if(edest == nil)
+ edest = broad;
+ memcpy(p, edest, 6);
+ memcpy(p + 6, mac, 6);
+ p[12] = 8;
+ p[13] = 6;
+ p += 14;
+ p = u32put(p, 0x00010800);
+ p = u32put(p, 0x06040000 | op);
+ memcpy(p, mac, 6);
+ p = u32put(p + 6, myip);
+ memcpy(p, edest, 6);
+ p = u32put(p + 6, idest);
+ ethtx(eth0, txbuf, p - txbuf);
+}
+
+void
+arpc(uchar *p)
+{
+ p += 14;
+ if(u32get(p) != 0x00010800 || p[4] != 6 || p[5] != 4 || p[6] != 0)
+ return;
+ switch(p[7]){
+ case 1:
+ if(myip != 0 && u32get(p + 24) == myip)
+ arp(2, p + 8, u32get(p + 14));
+ break;
+ case 2:
+ if(tftpip != 0 && u32get(p + 14) == tftpip)
+ memcpy(tmac, p + 8, 6);
+ break;
+ }
+}
+
+udp *
+udprx(void)
+{
+ uchar *p;
+ ulong v;
+ udp *u;
+
+ u = &urbuf;
+ for(;; ethnext()){
+ p = ethrx();
+ if(p == nil)
+ return nil;
+ if(p[12] != 8)
+ continue;
+ if(p[13] == 6){
+ arpc(p);
+ continue;
+ }
+ if(p[13] != 0)
+ continue;
+ p += ETHHEAD;
+ if((p[0] >> 4) != 4 || p[9] != 0x11)
+ continue;
+ v = u32get(p + 16);
+ if(v != (ulong) -1 && v != myip)
+ continue;
+ u->idest = v;
+ u->isrc = u32get(p + 12);
+ p += (p[0] & 0xf) << 2;
+ u->sport = p[0] << 8 | p[1];
+ u->dport = p[2] << 8 | p[3];
+ u->len = p[4] << 8 | p[5];
+ if(u->len < 8)
+ continue;
+ u->len -= 8;
+ if(u->len >= sizeof(u->data))
+ u->len = sizeof(u->data);
+ memcpy(u->data, p + 8, u->len);
+ ethnext();
+ return u;
+ }
+}
+
+void
+arpreq(void)
+{
+ uchar *p;
+
+ arp(1, nil, tftpip);
+ timeren(ARPTIMEOUT);
+ for(;; ethnext()){
+ p = ethrx();
+ if(p == nil){
+ print("ARP timeout\n");
+ timeren(ARPTIMEOUT);
+ arp(1, nil, tftpip);
+ }
+ if(p[12] != 8 || p[13] != 6)
+ continue;
+ arpc(p);
+ if(tmac[0] != 0xff)
+ break;
+ }
+ timeren(-1);
+}
+
+void
+dhcp(ulong *r)
+{
+ udp *u;
+ uchar *p;
+ uchar type;
+
+ xid = 0xdeadbeef;
+ tftpip = 0;
+ dhcppkg(r, DHCPDISCOVER);
+ timeren(DHCPTIMEOUT);
+ for(;;){
+ u = udprx();
+ if(u == nil){
+ timeren(DHCPTIMEOUT);
+ dhcppkg(r, DHCPDISCOVER);
+ print("DHCP timeout\n");
+ }
+ p = u->data;
+ if(u->dport != 68 || p[0] != 2 || u32get(p + 4) != xid || u32get(p + 236) != 0x63825363)
+ continue;
+ p += 240;
+ type = 0;
+ dhcpip = 0;
+ for(; p < u->data + u->len && *p != 0xff; p += 2 + p[1])
+ switch(*p){
+ case 53:
+ type = p[2];
+ break;
+ case 54:
+ dhcpip = u32get(p + 2);
+ break;
+ }
+ if(type != DHCPOFFER)
+ continue;
+ p = u->data;
+ if(p[108] == 0){
+ print("Offer from %I for %I with no boot file\n", dhcpip, u32get(p + 16));
+ continue;
+ }
+ myip = u32get(p + 16);
+ tftpip = u32get(p + 20);
+ memcpy(file, p + 108, 128);
+ print("Offer from %I for %I with boot file '%s' at %I\n", dhcpip, myip, file, tftpip);
+ break;
+ }
+ timeren(-1);
+ dhcppkg(r, DHCPREQUEST);
+}
+
+udp *
+tftppkg(void)
+{
+ udp *u;
+
+ u = &ubuf;
+ memcpy(u->edest, tmac, 6);
+ memcpy(u->esrc, mac, 6);
+ u->idest = tftpip;
+ u->isrc = myip;
+ u->sport = 69;
+ u->dport = 69;
+ return u;
+}
+
+void
+tftp(ulong *r, char *q, uintptr base)
+{
+ udp *u, *v;
+ uchar *p;
+ int bn, len;
+
+restart:
+ u = tftppkg();
+ p = u->data;
+ *p++ = 0;
+ *p++ = 1;
+ do
+ *p++ = *q;
+ while(*q++ != 0);
+ memcpy(p, "octet", 6);
+ p += 6;
+ u->len = p - u->data;
+ udptx(r, u);
+ timeren(TFTPTIMEOUT);
+
+ for(;;){
+ v = udprx();
+ if(v == nil){
+ print("TFTP timeout");
+ goto restart;
+ }
+ if(v->dport != 69 || v->isrc != tftpip || v->idest != myip)
+ continue;
+ if(v->data[0] != 0)
+ continue;
+ switch(v->data[1]){
+ case 3:
+ bn = v->data[2] << 8 | v->data[3];
+ len = v->len - 4;
+ if(len < 0)
+ continue;
+ if(len > 512)
+ len = 512;
+ memcpy((char*)base + ((bn - 1) << 9), v->data + 4, len);
+ if((bn & 127) == 0)
+ putc('.');
+ p = u->data;
+ *p++ = 0;
+ *p++ = 4;
+ *p++ = bn >> 8;
+ *p = bn;
+ u->len = 4;
+ udptx(r, u);
+ if(len < 512){
+ putc(10);
+ timeren(-1);
+ return;
+ }
+ timeren(TFTPTIMEOUT);
+ break;
+ case 5:
+ v->data[v->len - 1] = 0;
+ print("TFTP error: %s\n", v->data + 4);
+ timeren(-1);
+ return;
+ }
+ }
+}
+
+int
+netboot(void)
+{
+ ethinit(eth0);
+ myip = 0;
+ dhcp(eth0);
+ arpreq();
+ tftp(eth0, file, TZERO);
+ memset((void *) CONF, 0, CONFSIZE);
+ tftp(eth0, "/cfg/pxe/0ea7deadbeef", CONF);
+ return 1;
+}
--- /dev/null
+++ b/sys/src/boot/zynq/qspi.c
@@ -1,0 +1,45 @@
+#include <u.h>
+#include "dat.h"
+#include "fns.h"
+
+enum {
+ QSPI_CFG,
+ QSPI_STATUS,
+ QSPI_EN = 5,
+ QSPI_TXD4 = 7,
+ QSPI_RXD,
+ QSPI_TXD1 = 32,
+ QSPI_TXD2,
+ QSPI_TXD3
+};
+
+#define QSPI0 ((void *) 0xE000D000)
+
+static u32int
+cmd(ulong *r, int sz, u32int c)
+{
+ if(sz == 4)
+ r[QSPI_TXD4] = c;
+ else
+ r[QSPI_TXD1 + sz - 1] = c;
+ r[QSPI_CFG] |= 1<<16;
+ while((r[QSPI_STATUS] & (1<<2|1<<4)) != (1<<2|1<<4))
+ ;
+ return r[QSPI_RXD];
+}
+
+void
+flash(void)
+{
+ ulong *r;
+
+ r = QSPI0;
+ r[QSPI_CFG] = 1<<31 | 1<<19 | 3<<6 | 1<<15 | 1<<14 | 1<<10 | 1<<3 | 1;
+ r[QSPI_CFG] &= ~(1<<10);
+ r[QSPI_EN] = 1;
+ cmd(r, 1, 0x06);
+// cmd(r, 3, 0xD8);
+ for(;;)
+ print("%x\n", cmd(r, 2, 0x05));
+
+}