From 17ebe55031ae6945ad1f671b69267a672328e4b1 Mon Sep 17 00:00:00 2001 From: aiju Date: Wed, 8 Jan 2020 02:35:01 +0000 Subject: [PATCH] add cycv kernel --- sys/src/9/cycv/cycv | 55 ++++ sys/src/9/cycv/dat.h | 202 +++++++++++++ sys/src/9/cycv/devarch.c | 389 +++++++++++++++++++++++++ sys/src/9/cycv/fns.h | 78 +++++ sys/src/9/cycv/init9.s | 7 + sys/src/9/cycv/intr.c | 121 ++++++++ sys/src/9/cycv/io.h | 13 + sys/src/9/cycv/l.s | 502 ++++++++++++++++++++++++++++++++ sys/src/9/cycv/ltrap.s | 100 +++++++ sys/src/9/cycv/main.c | 316 ++++++++++++++++++++ sys/src/9/cycv/mem.h | 127 ++++++++ sys/src/9/cycv/mkfile | 89 ++++++ sys/src/9/cycv/mmu.c | 376 ++++++++++++++++++++++++ sys/src/9/cycv/timer.c | 112 ++++++++ sys/src/9/cycv/trap.c | 591 ++++++++++++++++++++++++++++++++++++++ sys/src/9/cycv/uartcycv.c | 243 ++++++++++++++++ sys/src/9/mkfile | 1 + sys/src/9/port/portmkfile | 2 +- 18 files changed, 3323 insertions(+), 1 deletion(-) create mode 100644 sys/src/9/cycv/cycv create mode 100644 sys/src/9/cycv/dat.h create mode 100644 sys/src/9/cycv/devarch.c create mode 100644 sys/src/9/cycv/fns.h create mode 100644 sys/src/9/cycv/init9.s create mode 100644 sys/src/9/cycv/intr.c create mode 100644 sys/src/9/cycv/io.h create mode 100644 sys/src/9/cycv/l.s create mode 100644 sys/src/9/cycv/ltrap.s create mode 100644 sys/src/9/cycv/main.c create mode 100644 sys/src/9/cycv/mem.h create mode 100644 sys/src/9/cycv/mkfile create mode 100644 sys/src/9/cycv/mmu.c create mode 100644 sys/src/9/cycv/timer.c create mode 100644 sys/src/9/cycv/trap.c create mode 100644 sys/src/9/cycv/uartcycv.c diff --git a/sys/src/9/cycv/cycv b/sys/src/9/cycv/cycv new file mode 100644 index 000000000..cc2e0aeaa --- /dev/null +++ b/sys/src/9/cycv/cycv @@ -0,0 +1,55 @@ +dev + root + cons + swap +# 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 + sd +# draw screen +# mouse +# usb + segment + +link + ethermedium + loopbackmedium + netdevmedium +# usbehci usbehcizynq + +misc + uartcycv +# sdmmc emmc + sdram + +ip + tcp + udp + rudp + ipifc + icmp + icmp6 + gre + ipmux + esp + +port + int cpuserver = 0; + +bootdir + /$objtype/bin/paqfs + /$objtype/bin/auth/factotum + boot + bootfs.paq diff --git a/sys/src/9/cycv/dat.h b/sys/src/9/cycv/dat.h new file mode 100644 index 000000000..7195e7ad7 --- /dev/null +++ b/sys/src/9/cycv/dat.h @@ -0,0 +1,202 @@ +typedef struct Conf Conf; +typedef struct Confmem Confmem; +typedef struct FPsave FPsave; +typedef struct PFPU PFPU; +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 Page Page; +typedef struct Proc Proc; +typedef struct PMMU PMMU; +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]; +}; + +struct PFPU +{ + int fpstate; + FPsave fpsave[1]; +}; + +enum +{ + FPinit, + FPactive, + FPinactive, + FPillegal = 0x100 +}; + +struct Confmem +{ + uintptr base; + usize npage; + uintptr kbase; + uintptr klimit; +}; + +struct Conf +{ + ulong nmach; /* processors */ + ulong nproc; /* processes */ + Confmem mem[2]; /* 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; +}; + +/* + * 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 */ + + ulong delayloop; + + /* stats */ + int tlbfault; + int tlbpurge; + int pfault; + int cs; + int syscall; + int load; + int intr; + 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]; +}; + +#define NISAOPT 8 +struct ISAConf +{ + char *type; + ulong port; + int irq; + int nopt; + char *opt[NISAOPT]; +}; +#define BUSUNKNOWN -1 + +struct +{ + char machs[MAXMACH]; /* active CPUs */ + int exiting; /* shutdown */ +}active; + +extern register Mach* m; /* R10 */ +extern register Proc* up; /* R9 */ + +extern int normalprint; + +void nope(void); +#define NOPE nope(); + +/* + * hardware info about a device + */ +typedef struct { + ulong port; + int size; +} Devport; + +struct DevConf +{ + ulong intnum; /* interrupt number */ + char *type; /* card type, malloced */ + int nports; /* Number of ports */ + Devport *ports; /* The ports themselves */ +}; + +#define mpcore ((ulong*)MPCORE_BASE) diff --git a/sys/src/9/cycv/devarch.c b/sys/src/9/cycv/devarch.c new file mode 100644 index 000000000..00a368fd6 --- /dev/null +++ b/sys/src/9/cycv/devarch.c @@ -0,0 +1,389 @@ +#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, + Qfbctl, + Qbase, + + Qmax = 16, +}; + +static Dirtab archdir[Qmax] = { + ".", { Qdir, 0, QTDIR }, 0, 0555, + "temp", { Qtemp, 0}, 0, 0440, + "pl", { Qpl, 0 }, 0, 0660, + "fbctl", { Qfbctl, 0 }, 0, 0660, +}; +static int narchdir = Qbase; + +static int temp = -128; +static ulong *devc; +static int dmadone; +enum { PLBUFSIZ = 8192 }; +static uchar *plbuf; +static Rendez plinitr, pldoner, pldmar; +static QLock plrlock, plwlock; +static Ref plwopen; +static Physseg *axi; + +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; + devc[DEVMASK] |= DONE; + axi->attr &= ~SG_FAULT; + wakeup(&pldoner); + } + if((fl & DMADONE) != 0){ + dmadone++; + wakeup(&pldmar); + } + devc[DEVISTS] = fl; +} + +static void +plinit(void) +{ + Physseg seg; + + memset(&seg, 0, sizeof seg); + seg.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC | SG_FAULT; + seg.name = "axi"; + seg.pa = 0x40000000; + seg.size = 0x8000000; + axi = addphysseg(&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; +} + +static void +plconf(void) +{ + axi->attr |= SG_FAULT; + procflushpseg(axi); + flushmmu(); + + slcr[0x240/4] = 0xf; + slcr[0x900/4] = 0xa; + devc[DEVISTS] = DONE|INITPE|DMADONE; + devc[DEVCTRL] |= PROG; + devc[DEVCTRL] &= ~PROG; + devc[DEVMASK] &= ~DONE; + devc[DEVCTRL] |= PROG; + + while(waserror()) + ; + sleep(&plinitr, isplinit, nil); + poperror(); +} + +static long +plwrite(uintptr pa, long n) +{ + dmadone = 0; + coherence(); + devc[DMASRC] = pa; + devc[DMADST] = -1; + devc[DMASRCL] = n>>2; + devc[DMADSTL] = 0; + + while(waserror()) + ; + sleep(&pldmar, isdmadone, nil); + poperror(); + + return n; +} + +static long +plcopy(uchar *d, long n) +{ + long ret; + ulong nn; + uintptr pa; + + if((n & 3) != 0 || n <= 0) + error(Eshort); + + eqlock(&plwlock); + if(waserror()){ + qunlock(&plwlock); + nexterror(); + } + + 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); + } + + qunlock(&plwlock); + poperror(); + + 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: + eqlock(&plrlock); + if(waserror()){ + qunlock(&plrlock); + nexterror(); + } + sleep(&pldoner, ispldone, nil); + qunlock(&plrlock); + poperror(); + return 0; + case Qfbctl: + return fbctlread(c, a, n, offset); + 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); + case Qfbctl: + return fbctlwrite(c, a, n, offset); + 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 || c->mode == ORDWR)){ + if(incref(&plwopen) != 1){ + c->flag &= ~COPEN; + decref(&plwopen); + error(Einuse); + } + plbuf = smalloc(PLBUFSIZ); + plconf(); + } + return c; +} + +static void +archclose(Chan* c) +{ + if((c->flag & COPEN) != 0) + if((ulong)c->qid.path == Qpl && (c->mode == OWRITE || c->mode == ORDWR)){ + free(plbuf); + plbuf = nil; + decref(&plwopen); + } +} + +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, +}; + diff --git a/sys/src/9/cycv/fns.h b/sys/src/9/cycv/fns.h new file mode 100644 index 000000000..6606c4ee4 --- /dev/null +++ b/sys/src/9/cycv/fns.h @@ -0,0 +1,78 @@ +#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 sendevent(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 timerinit(void); +void synccycles(void); +void setpmcr(ulong); +void setpmcnten(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); +long fbctlread(Chan*,void*,long,vlong); +long fbctlwrite(Chan*,void*,long,vlong); +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 *); +void dmaflush(int, void*, ulong); +void* ucalloc(ulong); +void clean2pa(uintptr, uintptr); +void inval2pa(uintptr, uintptr); +void archinit(void); +uintptr palookur(void *); +void screeninit(void); +int isaconfig(char*, int, ISAConf*); +void cputhex(u32int); diff --git a/sys/src/9/cycv/init9.s b/sys/src/9/cycv/init9.s new file mode 100644 index 000000000..8d6f11df4 --- /dev/null +++ b/sys/src/9/cycv/init9.s @@ -0,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 diff --git a/sys/src/9/cycv/intr.c b/sys/src/9/cycv/intr.c new file mode 100644 index 000000000..45a68f9ab --- /dev/null +++ b/sys/src/9/cycv/intr.c @@ -0,0 +1,121 @@ +#include "u.h" +#include +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +enum { + NINTR = 212, + 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; + + if(m->machno != 0) + return; + + /* 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 && irqs[irq].f != f) + 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(); + } +} diff --git a/sys/src/9/cycv/io.h b/sys/src/9/cycv/io.h new file mode 100644 index 000000000..dd0d90019 --- /dev/null +++ b/sys/src/9/cycv/io.h @@ -0,0 +1,13 @@ +#define UART_BASE 0xFFC02000 +#define MPCORE_BASE 0xFFFEC000 +#define L2_BASE 0xFFFEF000 +#define CLOCKMGR_BASE 0xFFD04000 + +#define HPS_CLK 25 + +#define TIMERIRQ 29 +#define UART0IRQ 194 + +#define LEVEL 0 +#define EDGE 1 + diff --git a/sys/src/9/cycv/l.s b/sys/src/9/cycv/l.s new file mode 100644 index 000000000..2bbe00a89 --- /dev/null +++ b/sys/src/9/cycv/l.s @@ -0,0 +1,502 @@ +#include "mem.h" +#include "io.h" + +#define PUTC(c) MOVW $(c), R0; MOVW R0, (R8) + +TEXT _start(SB), $-4 + MOVW $(KTZERO-KZERO), R13 + MOVW $(UART_BASE), R8 + + /* disable L2 cache */ + MOVW $0, R0 + MOVW $(L2_BASE+0x100), R1 + MOVW R0, (R1) + + PUTC('P') + /* disable MMU and L1 caches */ + MOVW $0x20c5047a, R1 + MOVW $_start0-KZERO(SB), R2 + MCR 15, 0, R1, C(1), C(0), 0 + MOVW R2, R15 + +TEXT _start0(SB), $-4 + DSB + ISB + PUTC('l') + + /* clean up to KTZERO */ + MOVW $0, R0 + MOVW R0, R1 + MOVW $(KTZERO-KZERO), R2 +_clrstart: + MOVW.P R0, 4(R1) + CMP.S R1, R2 + BGE _clrstart + + /* clean BSS */ + MOVW $edata-KZERO(SB), R1 + MOVW $end-KZERO(SB), R2 +_clrbss: + MOVW.P R0, 4(R1) + CMP.S R1, R2 + BGE _clrbss + + PUTC('a') + + /* KZERO to PERIPH is mapped to 0 */ + MOVW $SECSZ, R0 + MOVW $(MACHL1(0)-KZERO), R4 + MOVW $KZERO, R1 + ADD R1>>(SECSH-2), R4, R1 + MOVW $(L1SEC|L1CACHED|L1KERRW), R2 + MOVW $(PERIPH-KZERO), R3 +_start1: + MOVW.P R2, 4(R1) + ADD R0, R2 + CMP.S R2, R3 + BGE _start1 + + /* memory above PERIPH is mapped to itself */ + MOVW $(PERIPH|L1SEC|L1DEVICE|L1NOEXEC|L1KERRW), R2 +_start2: + MOVW.P R2, 4(R1) + ADD.S R0, R2 + BCC _start2 + + PUTC('n') + + MOVW $(MACH(0)-KZERO), R(Rmach) +_start3: + /* enable MMU permission checking */ + MOVW $0x55555555, R0 + MCR 15, 0, R0, C(3), C(0), 0 + + /* select page table and enable MMU */ + MOVW $0, R0 + MCR 15, 0, R0, C(8), C(7), 0 + DSB + ORR $TTBATTR, R4, 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 + + ADD $KZERO, R(Rmach) + MOVW R(Rmach), R13 + ADD $MACHSIZE, R13 + + MOVW R(Rmach), R0 + ADD $12, R0 + BL loadsp(SB) + + MOVW $vectors(SB), R1 + MCR 15, 0, R1, C(12), C(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|2|1<<6), R0 + MCR 15, 0, R0, C(1), C(0), 1 + MRC 15, 0, R0, C(1), C(0), 0 + ORR $(3<<11|1<<2), R0 + MCR 15, 0, R0, C(1), C(0), 0 + DSB + ISB + + MOVW $UART_BASE, R8 + PUTC('9') + + /* kernel Mach* in TPIDRPRW */ + MCR 15, 0, R(Rmach), C(13), C(0), 4 + + MOVW $setR12(SB), R12 + 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 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 $UART_BASE, R8 +TEXT puthex(SB), $0 +_p0: + MOVW 0x14(R8), R6 + AND.S $(1<<5), 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 cas(SB), $0 +TEXT cmpswap(SB), $0 + MOVW ov+4(FP), R1 + MOVW nv+8(FP), R2 +spincas: + LDREX (R0), R3 + CMP.S R3, R1 + BNE fail + STREX R2, (R0), R4 + CMP.S $0, R4 + BNE spincas + MOVW $1, R0 + DMB + RET +fail: + CLREX + MOVW $0, R0 + RET + +TEXT tas(SB), $0 +TEXT _tas(SB), $0 + 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 sendevent(SB), $0 + SEV + 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 + DSB /* errata */ + 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 setpmcnten(SB), $0 + MCR 15, 0, R0, C(9), C(12), 1 + 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 fprestore(SB), $0 + MOVM.IA.W (R0), [R1-R2] + VMSR(0xe, 1, FPEXC) + VMSR(0xe, 2, FPSCR) + WORD $0xecb00b20 + WORD $0xecf00b20 + RET + +TEXT fpsave(SB), $0 + VMRS(0xe, FPEXC, 1) + VMRS(0xe, FPSCR, 2) + MOVM.IA.W [R1-R2], (R0) + WORD $0xeca00b20 + WORD $0xece00b20 + /* wet floor */ + +TEXT fpoff(SB), $0 +TEXT fpclear(SB), $0 + MOVW $0, 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<>13, Rmaxset + AND $0x7fff, Rmaxset + MOVW Rmaxset<>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 + diff --git a/sys/src/9/cycv/ltrap.s b/sys/src/9/cycv/ltrap.s new file mode 100644 index 000000000..4334d2263 --- /dev/null +++ b/sys/src/9/cycv/ltrap.s @@ -0,0 +1,100 @@ +#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) + + /* get Mach* from TPIDRPRW */ + MRC 15, 0, R(Rmach), C(13), C(0), 4 + 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 + + /* get Mach* from TPIDRPRW */ + MRC 15, 0, R(Rmach), C(13), C(0), 4 + 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] diff --git a/sys/src/9/cycv/main.c b/sys/src/9/cycv/main.c new file mode 100644 index 000000000..48212fce4 --- /dev/null +++ b/sys/src/9/cycv/main.c @@ -0,0 +1,316 @@ +#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; + +enum { MAXCONF = 64 }; + +char *confname[MAXCONF], *confval[MAXCONF]; +int nconf; + +void +exit(int) +{ + cpushutdown(); + for(;;) idlehands(); +} + +void +reboot(void *, void *, ulong) +{ +} + +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: + memmove(p->fpsave, up->fpsave, sizeof(FPsave)); + p->fpstate = FPinactive; + } + splx(s); +} + +void +procsetup(Proc *p) +{ + p->fpstate = FPinit; + fpoff(); + + cycles(&p->kentry); + p->pcycles = -p->kentry; +} + +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; +} + +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) +{ + ulong kmem; + int i; + + conf.nmach = 1; + conf.nproc = 2000; + conf.ialloc = 16*1024*1024; + conf.nimage = 200; + conf.mem[0].base = PGROUND((ulong)end - KZERO); + conf.mem[0].npage = (1024*1024*1024 - conf.mem[0].base) >> PGSHIFT; + + ramdiskinit(); + + conf.npage = 0; + for(i = 0; i < nelem(conf.mem); i++) + conf.npage += conf.mem[i].npage; + + kmem = 200*1024*1024; + conf.upages = conf.npage - kmem/BY2PG; + kmem -= conf.upages*sizeof(Page) + + conf.nproc*sizeof(Proc) + + conf.nimage*sizeof(Image); + mainmem->maxsize = kmem; + imagmem->maxsize = kmem - (kmem/10); +} + +static void +init0(void) +{ + char buf[ERRMAX], **sp; + 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(); + + 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); + + sp = (char**)(USTKTOP - sizeof(Tos) - 8 - sizeof(sp[0])*4); + sp[3] = sp[2] = nil; + strcpy(sp[1] = (char*)&sp[4], "boot"); + sp[0] = nil; + 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); + segpage(s, pg); + v = tmpmap(pg->pa); + memset(v, 0, BY2PG); + tmpunmap(v); + + s = newseg(SG_TEXT, UTZERO, 1); + s->flushme++; + p->seg[TSEG] = s; + pg = newpage(0, 0, UTZERO); + pg->txtflush = ~0; + + 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 0; +} + +void +cpuidprint(void) +{ + print("cpu%d: %dMHz ARM Cortex-A9\n", m->machno, m->cpumhz); +} + +void +main(void) +{ + active.machs[m->machno] = 1; + if(m->machno != 0){ + uartputs("\n", 1); + mmuinit(); + intrinit(); + timerinit(); + cpuidprint(); + synccycles(); + timersinit(); + schedinit(); + return; + } + uartinit(); + mmuinit(); + intrinit(); + options(); + confinit(); + timerinit(); + uartputs(" from Bell Labs\n", 16); + xinit(); + printinit(); + quotefmtinstall(); + cpuidprint(); + sanity(); + todinit(); + timersinit(); + procinit0(); + initseg(); + if(delaylink) + bootlinks(); + else + links(); + chandevreset(); + pageinit(); + userinit(); + schedinit(); +} + +void +setupwatchpts(Proc *, Watchpt *, int n) +{ + if(n > 0) + error("no watchpoints"); +} diff --git a/sys/src/9/cycv/mem.h b/sys/src/9/cycv/mem.h new file mode 100644 index 000000000..6df34dc91 --- /dev/null +++ b/sys/src/9/cycv/mem.h @@ -0,0 +1,127 @@ +/* + * 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+0x100000) +#define TMAPSZ SECSZ +#define TMAP (KZERO - 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 MACHL1(n) (ROUND(MACH(MAXMACH), L1SZ) + (n)*L1SZ) +#define TMAPL2(n) (MACHL1(MAXMACH) + (n) * L2SZ) +#define TMAPL2SZ (MAXMACH * L2SZ) +#define CONFSIZE 65536 +#define CONFADDR (KTZERO-CONFSIZE) + +#define PERIPH 0xFF000000 + +#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 PTENOEXEC L2NOEXEC +#define PTECACHED L2CACHED +#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 SEV WORD $0xe320f004 +#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 0 +#define L1CACHED (1<<16|1<<14|1<<12|1<<2) +#define L1NOEXEC (1<<4) +#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 0 +#define L2NOEXEC (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|1<<1) diff --git a/sys/src/9/cycv/mkfile b/sys/src/9/cycv/mkfile new file mode 100644 index 000000000..f2920a265 --- /dev/null +++ b/sys/src/9/cycv/mkfile @@ -0,0 +1,89 @@ +CONF=cycv +CONFLIST=cycv + +#must match mem.h +KTZERO=0xf0100020 + +objtype=arm + init.h + +install:V: $p$CONF $p$CONF.u + cp $p$CONF $p$CONF.u /$objtype/ + for(i in $EXTRACOPIES) + import $i / /n/$i && cp $p$CONF $p$CONF.u /n/$i/$objtype/ diff --git a/sys/src/9/cycv/mmu.c b/sys/src/9/cycv/mmu.c new file mode 100644 index 000000000..d7fef9540 --- /dev/null +++ b/sys/src/9/cycv/mmu.c @@ -0,0 +1,376 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +void +mmuinit(void) +{ + m->l1.pa = ttbget(); + m->l1.va = KADDR(m->l1.pa); + memset((uchar*)TMAPL2(m->machno), 0, TMAPL2SZ); + 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(); + p = m->l1free; + if(p != nil){ + m->l1free = p->next; + p->next = nil; + m->nfree--; + splx(s); + return p; + } + splx(s); + 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(); + } + } + p->pa = PADDR(p->va); + memmove(p->va, m->l1.va, L1SZ); + 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) + panic("upalloc1: up->l1 != nil"); + up->l1 = p; + l1switch(p, 1); + splx(s); +} + +static void +l2free(Proc *proc) +{ + ulong *t; + Page *p, **l; + + if(proc->l1 == nil || proc->mmuused == nil) + return; + 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; + } + proc->l1->va[L1X(TMAP)] = 0; + *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; + ulong old; + uintptr l2p; + int s; + + if(up->l1 == nil) + upallocl1(); + e = &up->l1->va[L1RX(va)]; + if((*e & 3) == 0){ + p = up->mmufree; + if(p != nil) + up->mmufree = p->next; + else + p = newpage(0, 0, 0); + p->daddr = L1RX(va); + p->next = up->mmuused; + up->mmuused = p; + s = splhi(); + 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(); + }else{ + s = splhi(); + l2p = *e & ~(BY2PG - 1); + l2 = tmpmap(l2p); + } + e = &l2[L2RX(va)]; + old = *e; + *e = pa | L2VALID | L2USER | L2LOCAL; + tmpunmap(l2); + splx(s); + if((old & L2VALID) != 0) + flushpg((void *) va); + if(pg->txtflush & (1<machno)){ + cleandse((void *) va, (void *) (va + BY2PG)); + invalise((void *) va, (void *) (va + BY2PG)); + pg->txtflush &= ~(1<machno); + } +} + +void +checkmmu(uintptr, uintptr) +{ +} + +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) + pagechaindone(); + proc->mmufree = nil; +} + +uintptr +paddr(void *v) +{ + if((uintptr)v >= PERIPH) + return (uintptr)v; + if((uintptr)v >= KZERO) + return (uintptr)v-KZERO; + panic("paddr: va=%#p pc=%#p", v, getcallerpc(&v)); + return 0; +} + +void * +kaddr(uintptr u) +{ + if(u >= (uintptr)PERIPH) + return (void *)u; + if(u < (uintptr)-KZERO) + return (void *)(u + KZERO); + panic("kaddr: pa=%#p pc=%#p", u, getcallerpc(&u)); + return nil; +} + +uintptr +cankaddr(uintptr u) +{ + if(u >= (uintptr)PERIPH) + return -u; + if(u < (uintptr)-KZERO) + return PERIPH-KZERO - u; + return 0; +} + +KMap * +kmap(Page *page) +{ + ulong *e, *v; + int i, s; + + if(cankaddr(page->pa)) + return (KMap*)KADDR(page->pa); + 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); + up->nkmap++; + e = &up->l1->va[L1X(KMAP)]; + if((*e & 3) == 0){ + if(up->kmaptable != nil) + panic("kmaptable != nil"); + up->kmaptable = newpage(0, 0, 0); + s = 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); + splx(s); + *e = up->kmaptable->pa | L1PT; + coherence(); + return (KMap *) KMAP; + } + if(up->kmaptable == nil) + panic("kmaptable == nil"); + e = (ulong *) (KMAP + NKMAP * BY2PG); + for(i = 0; i < NKMAP; i++) + if((e[i] & 3) == 0){ + e[i] = page->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL; + coherence(); + return (KMap *) (KMAP + i * BY2PG); + } + panic("out of kmap"); + return nil; +} + +void +kunmap(KMap *arg) +{ + uintptr va; + ulong *e; + + va = (uintptr) arg; + if(va >= KZERO) + return; + 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; + + if(islo()) + panic("tmpmap: islow %#p", getcallerpc(&pa)); + 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; + + assert(m->l1.va[L1X(TMAP)] != 0); + if(up != nil && up->l1 != nil) + up->l1->va[L1X(TMAP)] = m->l1.va[L1X(TMAP)]; + + coherence(); + return (void *) ((u - ub) * BY2PG + TMAP); + } + 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); +} diff --git a/sys/src/9/cycv/timer.c b/sys/src/9/cycv/timer.c new file mode 100644 index 000000000..68cd20fa6 --- /dev/null +++ b/sys/src/9/cycv/timer.c @@ -0,0 +1,112 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#define clockmgr ((u32int*)(CLOCKMGR_BASE)) + +uvlong timerhz; + +enum { + TIMERDIV = 1, + LTIMERDIV = 1, + + GTIMERVALL = 0x200/4, + GTIMERVALH, + GTIMERCTL, + LTIMERVAL = 0x604/4, + LTIMERCTL, + LTIMERISR, +}; + +void +microdelay(int n) +{ + ulong now; + + now = µs(); + while(µs() - now < n); +} + +void +delay(int n) +{ + while(--n >= 0) + microdelay(1000); +} + +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) +{ + return fastticks2us(fastticks(nil)); +} + +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) +{ + u32int vco; + u64int hz; + int denum, numer, mpuclk; + + vco = clockmgr[0x40 / 4]; + denum = vco >> 16 & 0x3f; + numer = vco >> 3 & 0x1fff; + mpuclk = clockmgr[0x48 / 4] & 0x1ff; + + hz = HPS_CLK * 1000000 * (numer + 1) / ((denum + 1) * 2 * (mpuclk + 1)); + m->cpumhz = (hz + 500000) / 1000000; + m->cpuhz = hz; + timerhz = m->cpuhz / 4; + + mpcore[GTIMERCTL] = TIMERDIV - 1 << 8 | 3; + mpcore[LTIMERCTL] = LTIMERDIV - 1 << 8 | 4; + intrenable(TIMERIRQ, timerirq, nil, EDGE, "clock"); +} + +/* + * synchronize all cpu's cycle counter registers + */ +void +synccycles(void) +{ +} diff --git a/sys/src/9/cycv/trap.c b/sys/src/9/cycv/trap.c new file mode 100644 index 000000000..5dbe809b2 --- /dev/null +++ b/sys/src/9/cycv/trap.c @@ -0,0 +1,591 @@ +#include "u.h" +#include +#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("cpu%d: dumpstack\n", m->machno); + + x = 0; + x += iprint("ktrace /arm/9cycv %.8lux %.8lux %.8lux <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 char* +faulterr[0x20] = { +[0x01] "alignement fault", +[0x02] "debug event", +[0x04] "fault on instruction cache maintenance", +[0x08] "synchronous external abort", +[0x0C] "synchronous external abort on translation table walk L1", +[0x0E] "synchronous external abort on translation table walk L2", +[0x10] "tlb conflict abort", +[0x16] "asynchronous external abort", +[0x19] "synchronous parity error on memory access", +[0x1C] "synchronous parity error on translation table walk L1", +[0x1E] "synchronous parity error on translation table walk L2", +}; + +static void +faultarm(Ureg *ureg, ulong fsr, uintptr addr) +{ + int user, insyscall, read; + static char buf[ERRMAX]; + char *err; + + 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; + switch(fsr & 0x1F){ + case 0x05: /* translation fault L1 */ + case 0x07: /* translation fault L2 */ + case 0x03: /* access flag fault L1 */ + case 0x06: /* access flag fault L2 */ + case 0x09: /* domain fault L1 */ + case 0x0B: /* domain fault L2 */ + case 0x0D: /* permission fault L1 */ + case 0x0F: /* permission fault L2 */ + if(fault(addr, ureg->pc, read) == 0) + break; + /* wet floor */ + default: + err = faulterr[fsr & 0x1F]; + if(err == nil) + err = "fault"; + if(!user){ + dumpregs(ureg); + _dumpstack(ureg); + panic("kernel %s: pc=%#.8lux addr=%#.8lux fsr=%#.8lux", err, ureg->pc, addr, fsr); + } + sprint(buf, "sys: trap: %s %s addr=%#.8lux", err, read ? "read" : "write", addr); + postnote(up, 1, buf, NDebug); + } + up->insyscall = insyscall; +} + +static void +mathtrap(Ureg *, ulong) +{ + int s; + + if((up->fpstate & FPillegal) != 0){ + postnote(up, 1, "sys: floating point in note handler", NDebug); + return; + } + switch(up->fpstate){ + case FPinit: + s = splhi(); + fpinit(); + up->fpstate = FPactive; + splx(s); + break; + case FPinactive: + s = splhi(); + fprestore(up->fpsave); + up->fpstate = FPactive; + splx(s); + 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; + } + dumpregs(ureg); + 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: + iprint("cpu%d: unknown trap type %ulx\n", m->machno, 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(); + 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(); + 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(); + 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; + ureg->r0 = (uintptr) oureg; + ((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 *ureg) +{ + iprint("trap: %lux psr %8.8lux type %2.2lux pc %8.8lux link %8.8lux\n", + ureg->type, ureg->psr, ureg->type, ureg->pc, ureg->link); + iprint("R14 %8.8lux R13 %8.8lux R12 %8.8lux R11 %8.8lux R10 %8.8lux\n", + ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10); + iprint("R9 %8.8lux R8 %8.8lux R7 %8.8lux R6 %8.8lux R5 %8.8lux\n", + ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5); + iprint("R4 %8.8lux R3 %8.8lux R2 %8.8lux R1 %8.8lux R0 %8.8lux\n", + ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0); + iprint("pc %#lux link %#lux\n", ureg->pc, ureg->link); +} + +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); +} diff --git a/sys/src/9/cycv/uartcycv.c b/sys/src/9/cycv/uartcycv.c new file mode 100644 index 000000000..eebf3c71a --- /dev/null +++ b/sys/src/9/cycv/uartcycv.c @@ -0,0 +1,243 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +enum { + RBR = 0, + IER, + FCR, + LCR, + MCR, + LSR, + MSR, + SCR, + + IIR = FCR, +}; + +enum { + LSR_THRE = 1<<5, + LSR_DR = 1<<0, + + ENTXIRQ = 1<<1, + ENRXIRQ = 1<<0 +}; + +typedef struct Ctlr { + Lock; + ulong *r; + int irq, iena; +} Ctlr; + +Uart* uartenable(Uart *); + +extern PhysUart cycvphysuart; + +static Ctlr vctlr[1] = { + { + .r = (void *) UART_BASE, + .irq = UART0IRQ, + } +}; + +static Uart vuart[1] = { + { + .regs = &vctlr[0], + .name = "UART1", + .freq = 25000000, + .phys = &cycvphysuart, + .console = 1, + .baud = 115200, + } +}; + +void +uartinit(void) +{ + consuart = vuart; +} + +static Uart * +vuartpnp(void) +{ + return vuart; +} + +static void +vuartkick(Uart *uart) +{ + Ctlr *ct; + int i; + + if(uart->blocked) + return; + ct = uart->regs; + if((ct->r[LSR] & LSR_THRE) == 0) + return; + for(i = 0; i < 128; i++){ + if(uart->op >= uart->oe && uartstageoutput(uart) == 0) + break; + ct->r[RBR] = *uart->op++; + } +} + +static void +vuartintr(Ureg *, void *arg) +{ + Uart *uart; + Ctlr *c; + int ch, f; + + uart = arg; + c = uart->regs; + for(;;){ + f = c->r[IIR] & 15; + switch(f){ + case 6: USED(c->r[LSR]); break; + case 4: case 8: + while((c->r[LSR] & LSR_DR) != 0){ + ch = c->r[RBR]; + uartrecv(uart, ch); + } + break; + case 2: + vuartkick(uart); + break; + default: + return; + } + } +} + +static void +vuartenable(Uart *uart, int ie) +{ + Ctlr *c; + + c = uart->regs; + ilock(c); + while((c->r[LSR] & LSR_THRE) == 0) + ; + c->r[LCR] = 0x03; + c->r[FCR] = 0x1; + c->r[IER] = 0x0; + if(ie){ + if(!c->iena){ + intrenable(c->irq, vuartintr, uart, LEVEL, uart->name); + c->iena = 1; + } + c->r[IER] = ENTXIRQ | ENRXIRQ; + } + iunlock(c); +} + +static int +vuartgetc(Uart *uart) +{ + Ctlr *c; + + c = uart->regs; + while((c->r[LSR] & LSR_DR) == 0) + ; + return c->r[RBR]; +} + +static void +vuartputc(Uart *uart, int c) +{ + Ctlr *ct; + + ct = uart->regs; + while((ct->r[LSR] & LSR_THRE) == 0) + ; + ct->r[RBR] = c; + return; +} + +int +uartconsole(void) +{ + Uart *uart = vuart; + + if(up == nil) + return -1; + + if(uartenable(uart) != nil){ + serialoq = uart->oq; + uart->opens++; + consuart = uart; + } + return 0; +} + +int +vuartbits(Uart *uart, int n) +{ + Ctlr *c; + + c = uart->regs; + switch(n){ + case 5: c->r[LCR] = c->r[LCR] & ~3 | 0; return 0; + case 6: c->r[LCR] = c->r[LCR] & ~3 | 1; return 0; + case 7: c->r[LCR] = c->r[LCR] & ~3 | 2; return 0; + case 8: c->r[LCR] = c->r[LCR] & ~3 | 3; return 0; + default: + return -1; + } +} + +int +vuartbaud(Uart *, int n) +{ + print("uart baud %d\n", n); + return 0; +} + +int +vuartparity(Uart *uart, int p) +{ + Ctlr *c; + + c = uart->regs; + switch(p){ + case 'n': c->r[LCR] = c->r[LCR] & ~0x38; return 0; + case 'o': c->r[LCR] = c->r[LCR] & ~0x38 | 0x08; return 0; + case 'e': c->r[LCR] = c->r[LCR] & ~0x38 | 0x18; return 0; + default: + return -1; + } +} + +void +vuartnop(Uart *, int) +{ +} + +int +vuartnope(Uart *, int) +{ + return -1; +} + + +PhysUart cycvphysuart = { + .pnp = vuartpnp, + .enable = vuartenable, + .kick = vuartkick, + .getc = vuartgetc, + .putc = vuartputc, + .bits = vuartbits, + .baud = vuartbaud, + .parity = vuartparity, + + .stop = vuartnope, + .rts = vuartnop, + .dtr = vuartnop, + .dobreak = vuartnop, + .fifo = vuartnop, + .power = vuartnop, + .modemctl = vuartnop, +}; diff --git a/sys/src/9/mkfile b/sys/src/9/mkfile index 36c4f1678..d5a618daf 100644 --- a/sys/src/9/mkfile +++ b/sys/src/9/mkfile @@ -1,5 +1,6 @@ ARCH=\ bcm\ + cycv\ kw\ mtx\ omap\ diff --git a/sys/src/9/port/portmkfile b/sys/src/9/port/portmkfile index ef3cd69e5..efd892356 100644 --- a/sys/src/9/port/portmkfile +++ b/sys/src/9/port/portmkfile @@ -35,7 +35,7 @@ clean:V: mk $i.clean %.clean:V: - rm -f $stem.c [9bz]$stem [9bz]$stem.gz s[9bz]$stem boot$stem.* + rm -f $stem.c [9bz]$stem [9bz]$stem.gz [9bz]$stem.u s[9bz]$stem boot$stem.* nuke:V: clean rm -f ../boot/libboot.a$O *.elf *.rr *.acid