ref: 8e03baff8bbba541f87a435e596017e0bd7e5265
parent: 5e34f6ae06c4002cecda9027e759e94b0de0dc9e
author: Keegan Saunders <keegan@undefinedbehaviour.org>
date: Tue May 21 19:54:48 EDT 2024
add honeycomb kernel This is a kernel for the NXP LX2160A, specifically the SolidRun Honeycomb board which is available for sale on the SolidRun website. It currently boots on U-Boot. UEFI support is planned. Build or download the U-Boot firmware from the SolidRun site and then write it to the on-board SD card. Then, plug in a USB with the honeycomb image and proceed to install as normal. Only NVMe or USB storage is supported (SATA is planned). This kernel supports PCIe and USB. On-board ethernet and SFP are not supported (yet). It uses 2GB of memory by default, but that can be increased using *maxmem depending on how much RAM you have in the system. As well, SMP is currently disabled until an uncommon deadlock issue is fixed (could be a hardware issue, unknown at this point).
--- a/sys/lib/dist/mkfile
+++ b/sys/lib/dist/mkfile
@@ -126,6 +126,19 @@
mv $target.$pid.disk $target && dd -trunc 0 -bs 1024 -oseek 33 -if /n/src9/sys/src/boot/reform/flash.bin -of $target
}
+%.honeycomb.img:D: /n/src9/sys/src/boot/honeycomb/boot.scr
+ @{
+ objtype=arm64
+ kernel=/n/src9/$objtype/9honeycomb.u
+ > /env/plan9.ini {
+ echo 'console=0'
+ }
+ fatfiles=(/n/src9/sys/src/boot/honeycomb/boot.scr /env/plan9.ini $kernel)
+ mb=1885 # storage vendors idea of 2GB
+ mk $target.$pid.disk
+ mv $target.$pid.disk $target
+ }
+
%.pc.iso:D: $proto /n/src9/sys/lib/sysconfig/proto/9bootproto $kernel
@{rfork n
mk binds
@@ -186,7 +199,7 @@
disk/prep -bw -a^(nvram fs) $d/plan9
disk/format -d $d/dos $fatfiles
}
- if not if(~ $target *.reform.img.* *.arm64.qcow2.*){
+ if not if(~ $target *.reform.img.* *.arm64.qcow2.* *.honeycomb.img.*){
{
echo 'a p1 4M 100M'
echo 't p1 FAT32'
--- /dev/null
+++ b/sys/src/9/lx2k/archlx2k.c
@@ -1,0 +1,22 @@
+#include "u.h"
+#include "mem.h"
+
+enum {
+ /* ARM SBSA */
+ Wdogwcs = 0x00,
+};
+
+static void
+wdogoff(void)
+{
+ u32int *r = (u32int *)(VIRTIO+0x13a0000ULL);
+
+ /* Doghouse (Disable) */
+ r[Wdogwcs] = 0;
+}
+
+void
+archlx2klink(void)
+{
+ wdogoff();
+}
--- /dev/null
+++ b/sys/src/9/lx2k/clock.c
@@ -1,0 +1,134 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "../arm64/sysreg.h"
+
+static uvlong freq;
+
+enum {
+ Enable = 1<<0,
+ Imask = 1<<1,
+ Istatus = 1<<2,
+};
+
+void
+clockshutdown(void)
+{
+}
+
+static void
+localclockintr(Ureg *ureg, void *)
+{
+ timerintr(ureg, 0);
+}
+
+void
+clockinit(void)
+{
+ uvlong tstart, tend;
+ ulong t0, t1;
+
+ syswr(PMCR_EL0, 1<<6 | 7);
+ syswr(PMCNTENSET, 1<<31);
+ syswr(PMUSERENR_EL0, 1<<2);
+ syswr(CNTKCTL_EL1, 1<<1);
+
+ syswr(CNTP_TVAL_EL0, ~0UL);
+ syswr(CNTP_CTL_EL0, Enable);
+
+ if(m->machno == 0){
+ freq = sysrd(CNTFRQ_EL0);
+ print("timer frequency %lld Hz\n", freq);
+ }
+ tstart = sysrd(CNTPCT_EL0);
+ do{
+ t0 = lcycles();
+ }while(sysrd(CNTPCT_EL0) == tstart);
+ tend = tstart + (freq/100);
+ do{
+ t1 = lcycles();
+ }while(sysrd(CNTPCT_EL0) < tend);
+ t1 -= t0;
+ m->cpuhz = 100 * t1;
+ m->cpumhz = (m->cpuhz + Mhz/2 - 1) / Mhz;
+
+ /*
+ * we are using virtual counter register CNTVCT_EL0
+ * instead of the performance counter in userspace.
+ */
+ m->cyclefreq = freq;
+
+ intrenable(IRQcntpns, localclockintr, nil, BUSUNKNOWN, "clock");
+}
+
+void
+timerset(uvlong next)
+{
+ uvlong now;
+ long period;
+
+ now = fastticks(nil);
+ period = next - now;
+ syswr(CNTP_TVAL_EL0, period);
+}
+
+uvlong
+fastticks(uvlong *hz)
+{
+ if(hz)
+ *hz = freq;
+ return sysrd(CNTPCT_EL0);
+}
+
+ulong
+perfticks(void)
+{
+ return fastticks(nil);
+}
+
+ulong
+µs(void)
+{
+ uvlong hz;
+ uvlong t = fastticks(&hz);
+ return (t * 1000000ULL) / hz;
+}
+
+void
+microdelay(int n)
+{
+ ulong now;
+
+ now = µs();
+ while(µs() - now < n);
+}
+
+void
+delay(int n)
+{
+ while(--n >= 0)
+ microdelay(1000);
+}
+
+void
+synccycles(void)
+{
+ static Ref r1, r2;
+ int s;
+
+ s = splhi();
+ r2.ref = 0;
+ incref(&r1);
+ while(r1.ref != conf.nmach)
+ ;
+// syswr(PMCR_EL0, 1<<6 | 7);
+ incref(&r2);
+ while(r2.ref != conf.nmach)
+ ;
+ r1.ref = 0;
+ splx(s);
+}
--- /dev/null
+++ b/sys/src/9/lx2k/dat.h
@@ -1,0 +1,231 @@
+/*
+ * Time.
+ *
+ * HZ should divide 1000 evenly, ideally.
+ * 100, 125, 200, 250 and 333 are okay.
+ */
+#define HZ 100 /* clock frequency */
+#define MS2HZ (1000/HZ) /* millisec per clock tick */
+#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */
+
+enum {
+ Mhz = 1000 * 1000,
+
+ GpioLow = 0,
+ GpioHigh,
+ GpioRising,
+ GpioFalling,
+ GpioEdge,
+};
+
+typedef struct Conf Conf;
+typedef struct Confmem Confmem;
+typedef struct FPsave FPsave;
+typedef struct PFPU PFPU;
+typedef struct ISAConf ISAConf;
+typedef struct Label Label;
+typedef struct Lock Lock;
+typedef struct Memcache Memcache;
+typedef struct MMMU MMMU;
+typedef struct Mach Mach;
+typedef struct Page Page;
+typedef struct PhysUart PhysUart;
+typedef struct Pcidev Pcidev;
+typedef struct PMMU PMMU;
+typedef struct Proc Proc;
+typedef u64int PTE;
+typedef struct Soc Soc;
+typedef struct Uart Uart;
+typedef struct Ureg Ureg;
+typedef uvlong Tval;
+typedef void KMap;
+
+#pragma incomplete Pcidev
+#pragma incomplete Ureg
+
+#define MAXSYSARG 5 /* for mount(fd, mpt, flag, arg, srv) */
+
+/*
+ * parameters for sysproc.c
+ */
+#define AOUT_MAGIC (R_MAGIC)
+
+struct Lock
+{
+ ulong key;
+ u32int sr;
+ uintptr pc;
+ Proc* p;
+ Mach* m;
+ int isilock;
+};
+
+struct Label
+{
+ uintptr sp;
+ uintptr pc;
+};
+
+struct FPsave
+{
+ uvlong regs[32][2];
+
+ ulong control;
+ ulong status;
+};
+
+#define KFPSTATE
+
+struct PFPU
+{
+ int fpstate;
+ int kfpstate;
+ FPsave *fpsave;
+ FPsave *kfpsave;
+};
+
+enum
+{
+ FPinit,
+ FPactive,
+ FPinactive,
+ FPprotected,
+
+ /* bits or'd with the state */
+ FPillegal= 0x100,
+};
+
+struct Confmem
+{
+ uintptr base;
+ ulong npage;
+ uintptr limit;
+ uintptr kbase;
+ uintptr klimit;
+};
+
+struct Conf
+{
+ ulong nmach; /* processors */
+ ulong nproc; /* processes */
+ Confmem mem[3]; /* physical memory */
+ ulong npage; /* total physical pages of memory */
+ ulong 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 */
+ ulong hz; /* processor cycle freq */
+ ulong mhz;
+ int monitor; /* flag */
+};
+
+/*
+ * MMU stuff in Mach.
+ */
+struct MMMU
+{
+ PTE* mmutop; /* first level user page table */
+};
+
+/*
+ * MMU stuff in proc
+ */
+#define NCOLOR 1 /* 1 level cache, don't worry about VCE's */
+
+struct PMMU
+{
+ union {
+ Page *mmufree; /* mmuhead[0] is freelist head */
+ Page *mmuhead[PTLEVELS];
+ };
+ Page *mmutail[PTLEVELS];
+ int asid;
+ uintptr tpidr;
+};
+
+#include "../port/portdat.h"
+
+struct Mach
+{
+ int machno; /* physical id of processor */
+ uintptr splpc; /* pc of last caller to splhi */
+ Proc* proc; /* current process on this processor */
+ /* end of offsets known to asm */
+
+ MMMU;
+
+ PMach;
+
+ int fpstate;
+ FPsave *fpsave;
+
+ int cputype;
+ ulong delayloop;
+ int cpumhz;
+ uvlong cpuhz; /* speed of cpu */
+
+ int stack[1];
+};
+
+struct
+{
+ char machs[MAXMACH]; /* active CPUs */
+ int exiting; /* shutdown */
+}active;
+
+#define MACHP(n) ((Mach*)MACHADDR(n))
+
+extern register Mach* m; /* R27 */
+extern register Proc* up; /* R26 */
+extern int normalprint;
+
+/*
+ * a parsed plan9.ini line
+ */
+#define NISAOPT 8
+
+struct ISAConf {
+ char *type;
+ uvlong port;
+ int irq;
+ ulong dma;
+ ulong mem;
+ ulong size;
+ ulong freq;
+
+ int nopt;
+ char *opt[NISAOPT];
+};
+
+/*
+ * Horrid. But the alternative is 'defined'.
+ */
+#ifdef _DBGC_
+#define DBGFLG (dbgflg[_DBGC_])
+#else
+#define DBGFLG (0)
+#endif /* _DBGC_ */
+
+int vflag;
+extern char dbgflg[256];
+
+#define dbgprint print /* for now */
+
+/*
+ * 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 */
+};
--- /dev/null
+++ b/sys/src/9/lx2k/fns.h
@@ -1,0 +1,172 @@
+#include "../port/portfns.h"
+
+/* l.s */
+extern void sev(void);
+extern int tas(void *);
+extern int cmpswap(long*, long, long);
+extern void coherence(void);
+extern void idlehands(void);
+extern uvlong vcycles(void);
+#define cycles(ip) *(ip) = vcycles()
+extern int splfhi(void);
+extern void splflo(void);
+extern void touser(uintptr sp);
+extern void forkret(void);
+extern void noteret(void);
+extern void returnto(void*);
+extern void fpon(void);
+extern void fpoff(void);
+extern void fpsaveregs(void*);
+extern void fploadregs(void*);
+extern void smccall(Ureg*);
+
+extern void setttbr(uintptr pa);
+extern uintptr getfar(void);
+
+extern void flushasidva(uintptr asidva);
+extern void tlbivae1is(uintptr asidva);
+
+extern void flushasidvall(uintptr asidva);
+extern void tlbivale1is(uintptr asidva);
+
+extern void flushasid(uintptr asid);
+extern void tlbiaside1is(uintptr asid);
+
+extern void flushtlb(void);
+extern void tlbivmalle1(void);
+
+extern void flushlocaltlb(void);
+extern void tlbivmalle1(void);
+
+/* cache */
+extern ulong cachesize(int level);
+
+extern void cacheiinvse(void*, int);
+extern void cacheuwbinv(void);
+extern void cacheiinv(void);
+
+extern void cachedwbse(void*, int);
+extern void cacheduwbse(void*, int);
+extern void cachedinvse(void*, int);
+extern void cachedwbinvse(void*, int);
+
+extern void cachedwb(void);
+extern void cachedinv(void);
+extern void cachedwbinv(void);
+
+extern void l2cacheuwb(void);
+extern void l2cacheuinv(void);
+extern void l2cacheuwbinv(void);
+
+/* mmu */
+#define getpgcolor(a) 0
+extern uintptr paddr(void*);
+#define PADDR(a) paddr((void*)(a))
+extern uintptr cankaddr(uintptr);
+extern void* kaddr(uintptr);
+#define KADDR(a) kaddr(a)
+extern void kmapinval(void);
+#define VA(k) ((uintptr)(k))
+extern KMap *kmap(Page*);
+extern void kunmap(KMap*);
+extern void kmapram(uintptr, uintptr);
+extern uintptr mmukmap(uintptr, uintptr, usize);
+extern void* vmap(uvlong, vlong);
+extern void vunmap(void*, vlong);
+extern void mmu1init(void);
+extern void putasid(Proc*);
+
+/* mem */
+extern void mmuidmap(uintptr*);
+extern void mmu0init(uintptr*);
+extern void meminit(void);
+
+extern void* ucalloc(usize);
+
+/* clock */
+extern void clockinit(void);
+extern void synccycles(void);
+extern void armtimerset(int);
+extern void clockshutdown(void);
+
+/* fpu */
+extern void fpuinit(void);
+extern void fpuprocsetup(Proc*);
+extern void fpuprocfork(Proc*);
+extern void fpuprocsave(Proc*);
+extern void fpuprocrestore(Proc*);
+extern FPsave* fpukenter(Ureg*);
+extern void fpukexit(Ureg*, FPsave*);
+extern void mathtrap(Ureg*);
+
+/* trap */
+extern void trapinit(void);
+extern int userureg(Ureg*);
+extern void evenaddr(uintptr);
+extern void setkernur(Ureg*, Proc*);
+extern void procfork(Proc*);
+extern void procsetup(Proc*);
+extern void procsave(Proc*);
+extern void procrestore(Proc *);
+extern void trap(Ureg*);
+extern void syscall(Ureg*);
+extern void noted(Ureg*, ulong);
+extern void faultarm64(Ureg*);
+extern void dumpstack(void);
+extern void dumpregs(Ureg*);
+
+/* irq */
+extern void intrinit(void);
+extern void intrcpushutdown(void);
+extern void intrsoff(void);
+extern void intrenable(int, void (*)(Ureg*, void*), void*, int, char*);
+extern void intrdisable(int, void (*)(Ureg*, void*), void*, int, char*);
+extern int irq(Ureg*);
+extern void fiq(Ureg*);
+
+/* sysreg */
+extern uvlong sysrd(ulong);
+extern void syswr(ulong, uvlong);
+
+/* uartlx2k */
+extern void uartconsinit(void);
+
+/* dma */
+extern void dmaflush(int, void*, ulong);
+
+/* main */
+extern char *getconf(char *name);
+extern void setconfenv(void);
+extern void writeconf(void);
+
+extern int isaconfig(char*, int, ISAConf*);
+extern void links(void);
+
+/* ccm */
+extern void setclkgate(char *name, int on);
+extern void setclkrate(char *name, char *source, int freq);
+extern int getclkrate(char *name);
+
+/* gpc */
+extern void powerup(char *dom);
+
+/* lcd */
+extern void lcdinit(void);
+
+/* iomux */
+extern void iomuxpad(char *pads, char *sel, char *cfg);
+extern uint iomuxgpr(int gpr, uint set, uint mask);
+
+/* gpio */
+#define GPIO_PIN(n, m) ((n)<<5 | (m))
+extern void gpioout(uint pin, int set);
+extern int gpioin(uint pin);
+void gpiointrenable(uint pin, int mode, void (*f)(uint pin, void *a), void *a);
+void gpiointrdisable(uint pin);
+
+/* pcilx2k */
+extern int pcicfgrw8(int tbdf, int rno, int data, int read);
+extern int pcicfgrw16(int tbdf, int rno, int data, int read);
+extern int pcicfgrw32(int tbdf, int rno, int data, int read);
+extern void pciintrenable(int tbdf, void (*f)(Ureg*, void*), void *a);
+extern void pciintrdisable(int tbdf, void (*f)(Ureg*, void*), void *a);
--- /dev/null
+++ b/sys/src/9/lx2k/gic.c
@@ -1,0 +1,319 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+#include "ureg.h"
+#include "../arm64/sysreg.h"
+#include "../port/error.h"
+
+enum {
+ GICD_CTLR = 0x000/4, /* RW, Distributor Control Register */
+ GICD_TYPER = 0x004/4, /* RO, Interrupt Controller Type */
+ GICD_IIDR = 0x008/4, /* RO, Distributor Implementer Identification Register */
+
+ GICD_IGROUPR0 = 0x080/4, /* RW, Interrupt Group Registers (0x80-0xBC) */
+
+ GICD_ISENABLER0 = 0x100/4, /* RW, Interrupt Set-Enable Registers (0x100-0x13C) */
+ GICD_ICENABLER0 = 0x180/4, /* RW, Interrupt Clear-Enable Registers (0x180-0x1BC) */
+
+ GICD_ISPENDR0 = 0x200/4, /* RW, Interrupt Set-Pending Registers (0x200-0x23C) */
+ GICD_ICPENDR0 = 0x280/4, /* RW, Interrupt Clear-Pending Registers (0x280-0x2BC) */
+
+ GICD_ISACTIVER0 = 0x300/4, /* RW, Interrupt Set-Active Registers (0x300-0x33C) */
+ GICD_ICACTIVER0 = 0x380/4, /* RW, Interrupt Clear-Active Registers (0x380-0x3BC) */
+
+ GICD_IPRIORITYR0= 0x400/4, /* RW, Interrupt Priority Registers (0x400-0x5FC) */
+ GICD_TARGETSR0 = 0x800/4, /* RW, Interrupt Target Registers (0x800-0x9FC) */
+ GICD_ICFGR0 = 0xC00/4, /* RW, Interrupt Configuration Registers (0xC00-0xC7C) */
+
+ GICD_ISR0 = 0xD00/4,
+ GICD_PPISR = GICD_ISR0, /* RO, Private Peripheral Interrupt Status Register */
+ GICD_SPISR0 = GICD_ISR0+1, /* RO, Shared Peripheral Interrupt Status Register */
+ GICD_SGIR = 0xF00/4, /* WO, Software Generated Interrupt Register */
+
+ GICD_CPENDSGIR0 = 0xF10/4, /* RW, SGI Clear-Pending Registers (0xF10-0xF1C) */
+ GICD_SPENDSGIR0 = 0xF20/4, /* RW, SGI Set-Pending Registers (0xF20-0xF2C) */
+
+ GICD_PIDR4 = 0xFD0/4, /* RO, Perpheral ID Registers */
+ GICD_PIDR5 = 0xFD4/4,
+ GICD_PIDR6 = 0xFD8/4,
+ GICD_PIDR7 = 0xFDC/4,
+ GICD_PIDR0 = 0xFE0/4,
+ GICD_PIDR1 = 0xFE4/4,
+ GICD_PIDR2 = 0xFE8/4,
+ GICD_PIDR3 = 0xFEC/4,
+
+ GICD_CIDR0 = 0xFF0/4, /* RO, Component ID Registers */
+ GICD_CIDR1 = 0xFF4/4,
+ GICD_CIDR2 = 0xFF8/4,
+ GICD_CIDR3 = 0xFFC/4,
+
+ RD_base = 0x00000,
+ GICR_CTLR = (RD_base+0x000)/4,
+ GICR_IIDR = (RD_base+0x004)/4,
+ GICR_TYPER = (RD_base+0x008)/4,
+ GICR_STATUSR = (RD_base+0x010)/4,
+ GICR_WAKER = (RD_base+0x014)/4,
+ GICR_SETLPIR = (RD_base+0x040)/4,
+ GICR_CLRLPIR = (RD_base+0x048)/4,
+ GICR_PROPBASER = (RD_base+0x070)/4,
+ GICR_PENDBASER = (RD_base+0x078)/4,
+ GICR_INVLPIR = (RD_base+0x0A0)/4,
+ GICR_INVALLR = (RD_base+0x0B0)/4,
+ GICR_SYNCR = (RD_base+0x0C0)/4,
+
+ SGI_base = 0x10000,
+ GICR_IGROUPR0 = (SGI_base+0x080)/4,
+ GICR_ISENABLER0 = (SGI_base+0x100)/4,
+ GICR_ICENABLER0 = (SGI_base+0x180)/4,
+ GICR_ISPENDR0 = (SGI_base+0x200)/4,
+ GICR_ICPENDR0 = (SGI_base+0x280)/4,
+ GICR_ISACTIVER0 = (SGI_base+0x300)/4,
+ GICR_ICACTIVER0 = (SGI_base+0x380)/4,
+ GICR_IPRIORITYR0= (SGI_base+0x400)/4,
+ GICR_ICFGR0 = (SGI_base+0xC00)/4,
+ GICR_ICFGR1 = (SGI_base+0xC04)/4,
+ GICR_IGRPMODR0 = (SGI_base+0xD00)/4,
+ GICR_NSACR = (SGI_base+0xE00)/4,
+};
+
+typedef struct Vctl Vctl;
+struct Vctl {
+ Vctl *next;
+ void (*f)(Ureg*, void*);
+ void *a;
+ int irq;
+ u32int intid;
+};
+
+static Lock vctllock;
+static Vctl *vctl[MAXMACH][32], *vfiq;
+static u32int *dregs = (u32int*)(VIRTIO + 0x5000000);
+
+static u32int*
+getrregs(int machno)
+{
+ u32int *rregs = (u32int*)(VIRTIO + 0x5200000);
+
+ for(;;){
+ if((rregs[GICR_TYPER] & 0xFFFF00) == (machno << 8))
+ return rregs;
+ if(rregs[GICR_TYPER] & (1<<4))
+ break;
+ rregs += (0x20000/4);
+ }
+ panic("getrregs: no re-distributor for cpu %d\n", machno);
+ return nil;
+}
+
+void
+intrcpushutdown(void)
+{
+ /* disable cpu interface */
+ syswr(ICC_IGRPEN1_EL1, 0);
+ coherence();
+}
+
+void
+intrsoff(void)
+{
+ /* disable distributor */
+ dregs[GICD_CTLR] = 0;
+ coherence();
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+}
+
+void
+intrinit(void)
+{
+ u32int *rregs;
+ int i, n;
+
+ if(m->machno == 0){
+ intrsoff();
+
+ /* clear all interrupts */
+ n = ((dregs[GICD_TYPER] & 0x1F)+1) << 5;
+ for(i = 32; i < n; i += 32){
+ dregs[GICD_IGROUPR0 + (i/32)] = -1;
+
+ dregs[GICD_ISENABLER0 + (i/32)] = -1;
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ dregs[GICD_ICENABLER0 + (i/32)] = -1;
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ dregs[GICD_ICACTIVER0 + (i/32)] = -1;
+ }
+ for(i = 0; i < n; i += 4){
+ dregs[GICD_IPRIORITYR0 + (i/4)] = 0;
+ dregs[GICD_TARGETSR0 + (i/4)] = 0;
+ }
+ for(i = 32; i < n; i += 16){
+ dregs[GICD_ICFGR0 + (i/16)] = 0;
+ }
+ coherence();
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ dregs[GICD_CTLR] = (1<<0) | (1<<1) | (1<<4);
+ }
+
+ rregs = getrregs(m->machno);
+ n = 32;
+ for(i = 0; i < n; i += 32){
+ rregs[GICR_IGROUPR0 + (i/32)] = -1;
+
+ rregs[GICR_ISENABLER0 + (i/32)] = -1;
+ while(rregs[GICR_CTLR]&(1<<3))
+ ;
+ rregs[GICR_ICENABLER0 + (i/32)] = -1;
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ rregs[GICR_ICACTIVER0 + (i/32)] = -1;
+ }
+ for(i = 0; i < n; i += 4){
+ rregs[GICR_IPRIORITYR0 + (i/4)] = 0;
+ }
+ coherence();
+ while(rregs[GICR_CTLR]&(1<<3))
+ ;
+
+ coherence();
+
+ /* enable cpu interface */
+ syswr(ICC_CTLR_EL1, 0);
+ syswr(ICC_BPR1_EL1, 7);
+ syswr(ICC_PMR_EL1, 0xFF);
+
+ coherence();
+}
+
+
+/*
+ * called by trap to handle irq interrupts.
+ * returns true iff a clock interrupt, thus maybe reschedule.
+ */
+int
+irq(Ureg* ureg)
+{
+ Vctl *v;
+ int clockintr;
+ u32int intid;
+
+ m->intr++;
+ intid = sysrd(ICC_IAR1_EL1) & 0xFFFFFF;
+// iprint("i<%d>", intid);
+ if((intid & ~3) == 1020)
+ return 0; // spurious
+ clockintr = 0;
+ for(v = vctl[m->machno][intid%32]; v != nil; v = v->next)
+ if(v->intid == intid){
+ coherence();
+ v->f(ureg, v->a);
+ coherence();
+ if(v->irq == IRQcntpns)
+ clockintr = 1;
+ }
+ coherence();
+ syswr(ICC_EOIR1_EL1, intid);
+ return clockintr;
+}
+
+/*
+ * called direct from lexception.s to handle fiq interrupt.
+ */
+void
+fiq(Ureg *ureg)
+{
+ Vctl *v;
+ u32int intid;
+
+ m->intr++;
+ intid = sysrd(ICC_IAR1_EL1) & 0xFFFFFF;
+// iprint("f<%d>", intid);
+ if((intid & ~3) == 1020)
+ return; // spurious
+ v = vfiq;
+ if(v != nil && v->intid == intid && m->machno == 0){
+ coherence();
+ v->f(ureg, v->a);
+ coherence();
+ }
+ syswr(ICC_EOIR1_EL1, intid);
+}
+
+void
+intrenable(int irq, void (*f)(Ureg*, void*), void *a, int tbdf, char *)
+{
+ Vctl *v;
+ u32int intid;
+ int cpu, prio;
+
+ if(BUSTYPE(tbdf) == BusPCI){
+ pciintrenable(tbdf, f, a);
+ return;
+ }
+
+ if(tbdf != BUSUNKNOWN)
+ return;
+
+ prio = 0x80;
+ intid = irq;
+ if((v = xalloc(sizeof(Vctl))) == nil)
+ panic("intrenable: no mem");
+ v->irq = irq;
+ v->intid = intid;
+ v->f = f;
+ v->a = a;
+
+ lock(&vctllock);
+ if(intid < SPI)
+ cpu = m->machno;
+ else
+ cpu = 0;
+ if(irq == IRQfiq){
+ vfiq = v;
+ prio = 0;
+ }else{
+ v->next = vctl[cpu][intid%32];
+ vctl[cpu][intid%32] = v;
+ }
+ syswr(ICC_IGRPEN1_EL1, sysrd(ICC_IGRPEN1_EL1)|1);
+ coherence();
+
+ syswr(ICC_EOIR1_EL1, intid);
+ coherence();
+
+ /* setup */
+ if(intid < 32){
+ u32int *rregs = getrregs(cpu);
+ rregs[GICR_IPRIORITYR0 + (intid/4)] |= prio << ((intid%4) << 3);
+ coherence();
+ rregs[GICR_ISENABLER0] = 1 << (intid%32);
+ coherence();
+ while(rregs[GICR_CTLR]&(1<<3))
+ ;
+ } else {
+ dregs[GICD_IPRIORITYR0 + (intid/4)] |= prio << ((intid%4) << 3);
+ dregs[GICD_TARGETSR0 + (intid/4)] |= (1<<cpu) << ((intid%4) << 3);
+ coherence();
+ dregs[GICD_ISENABLER0 + (intid/32)] = 1 << (intid%32);
+ coherence();
+ while(dregs[GICD_CTLR]&(1<<31))
+ ;
+ }
+ unlock(&vctllock);
+}
+
+void
+intrdisable(int, void (*f)(Ureg*, void*), void *a, int tbdf, char*)
+{
+ if(BUSTYPE(tbdf) == BusPCI){
+ pciintrdisable(tbdf, f, a);
+ return;
+ }
+}
--- /dev/null
+++ b/sys/src/9/lx2k/honeycomb
@@ -1,0 +1,51 @@
+dev
+ root
+ cons
+ swap
+ env
+ pipe
+ proc
+ mnt
+ srv
+ shr
+ dup
+ tls
+ cap
+ fs
+ ether netif
+ bridge log
+ ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
+ uart
+ usb
+ pci pci
+ sd
+
+link
+ usbxhcilx2k usbxhci
+ ethersink
+ ethermedium
+ loopbackmedium
+ netdevmedium
+ pcilx2k pci
+ archlx2k
+
+ip
+ tcp
+ udp
+ il
+ ipifc
+ icmp
+ icmp6
+ igmp
+ ipmux
+misc
+ gic
+ uartlx2k
+ sdnvme pci
+port
+ int cpuserver = 0;
+bootdir
+ /$objtype/bin/paqfs
+ /$objtype/bin/auth/factotum
+ bootfs.paq
+ boot
--- /dev/null
+++ b/sys/src/9/lx2k/io.h
@@ -1,0 +1,21 @@
+enum {
+ IRQfiq = -1,
+
+ PPI = 16,
+ SPI = 32,
+
+ IRQcntps = PPI+13,
+ IRQcntpns = PPI+14,
+
+ IRQuart = SPI+32,
+
+ IRQusb1 = SPI+80,
+ IRQusb2 = SPI+81,
+
+ IRQpci3 = SPI+119,
+ IRQpci5 = SPI+129,
+};
+
+#define BUSUNKNOWN (-1)
+#define PCIWINDOW 0
+#define PCIWADDR(x) (PADDR(x)+PCIWINDOW)
--- /dev/null
+++ b/sys/src/9/lx2k/l.s
@@ -1,0 +1,729 @@
+#include "mem.h"
+#include "../arm64/sysreg.h"
+
+#undef SYSREG
+#define SYSREG(op0,op1,Cn,Cm,op2) SPR(((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5))
+
+TEXT _start(SB), 1, $-4
+ MOV R0, R26 /* save */
+
+ MOV $setSB-KZERO(SB), R28
+ BL svcmode<>(SB)
+
+ /* use dedicated stack pointer per exception level */
+ MOVWU $1, R1
+ MSR R1, SPSel
+
+ BL mmudisable<>(SB)
+
+ /* invalidate local caches */
+ BL cachedwbinv(SB)
+ BL l2cacheuwbinv(SB)
+ BL cacheiinv(SB)
+
+ /* getmachno in R0 */
+ MRS MPIDR_EL1, R0
+ BL mpidindex(SB)
+
+ /* get MACHP(R0) in R27 */
+ MOV $(MACHADDR(0)-KZERO), R27
+ MOVWU $MACHSIZE, R2
+ MULW R0, R2, R2
+ SUB R2, R27
+
+ /* set the stack pointer */
+ ADD $(MACHSIZE-16), R27, R1
+ MOV R1, SP
+
+ CBNZ R0, _startup
+
+ /* clear page table and machs */
+ MOV $(L1BOT-KZERO), R1
+ MOV $(MACHADDR(-1)-KZERO), R2
+_zerol1:
+ MOV ZR, (R1)8!
+ CMP R1, R2
+ BNE _zerol1
+
+ /* clear BSS */
+ MOV $edata-KZERO(SB), R1
+ MOV $end-KZERO(SB), R2
+_zerobss:
+ MOV ZR, (R1)8!
+ CMP R1, R2
+ BNE _zerobss
+
+ /* setup page tables */
+ MOV $(L1BOT-KZERO), R0
+ BL mmuidmap(SB)
+
+ MOV $(L1-KZERO), R0
+ BL mmu0init(SB)
+
+ SEVL
+_startup:
+ WFE
+ BL mmuenable<>(SB)
+
+ MOV R26, R0
+ MOV $0, R26
+ ORR $KZERO, R27
+ MSR R27, TPIDR_EL1
+ MOV $setSB(SB), R28
+
+ BL main(SB)
+
+TEXT stop<>(SB), 1, $-4
+_stop:
+ WFE
+ B _stop
+
+TEXT sev(SB), 1, $-4
+ SEV
+ WFE
+ RETURN
+
+TEXT svcmode<>(SB), 1, $-4
+ MSR $0xF, DAIFSet
+ MRS CurrentEL, R0
+ ANDW $(3<<2), R0
+ CMPW $(1<<2), R0
+ BEQ el1
+ CMPW $(2<<2), R0
+ BEQ el2
+ B stop<>(SB)
+el2:
+ MOV $0, R0
+ MSR R0, MDCR_EL2
+ ISB $SY
+
+ /* set virtual timer offset to zero */
+ MOV $0, R0
+ MSR R0, CNTVOFF_EL2
+
+ /* HCR = RW, HCD, SWIO, BSU, FB */
+ MOVWU $(1<<31 | 1<<29 | 1<<2 | 0<<10 | 0<<9), R0
+ MSR R0, HCR_EL2
+ ISB $SY
+
+ /* SCTLR = RES1 */
+ MOVWU $(3<<4 | 1<<11 | 1<<16 | 1<<18 | 3<<22 | 3<<28), R0
+ ISB $SY
+ MSR R0, SCTLR_EL2
+ ISB $SY
+
+ /* set VMID to zero */
+ MOV $0, R0
+ MSR R0, VTTBR_EL2
+ ISB $SY
+
+ MOVWU $(0xF<<6 | 4), R0
+ MSR R0, SPSR_EL2
+ MSR LR, ELR_EL2
+ ERET
+el1:
+ RETURN
+
+TEXT mmudisable<>(SB), 1, $-4
+#define SCTLRCLR \
+ /* RES0 */ ( 3<<30 \
+ /* RES0 */ | 1<<27 \
+ /* UCI */ | 1<<26 \
+ /* EE */ | 1<<25 \
+ /* RES0 */ | 1<<21 \
+ /* E0E */ | 1<<24 \
+ /* WXN */ | 1<<19 \
+ /* nTWE */ | 1<<18 \
+ /* RES0 */ | 1<<17 \
+ /* nTWI */ | 1<<16 \
+ /* UCT */ | 1<<15 \
+ /* DZE */ | 1<<14 \
+ /* RES0 */ | 1<<13 \
+ /* RES0 */ | 1<<10 \
+ /* UMA */ | 1<<9 \
+ /* SA0 */ | 1<<4 \
+ /* SA */ | 1<<3 \
+ /* A */ | 1<<1 )
+#define SCTLRSET \
+ /* RES1 */ ( 3<<28 \
+ /* RES1 */ | 3<<22 \
+ /* RES1 */ | 1<<20 \
+ /* RES1 */ | 1<<11 )
+#define SCTLRMMU \
+ /* I */ ( 1<<12 \
+ /* C */ | 1<<2 \
+ /* M */ | 1<<0 )
+
+ /* initialise SCTLR, MMU and caches off */
+ ISB $SY
+ MRS SCTLR_EL1, R0
+ BIC $(SCTLRCLR | SCTLRMMU), R0
+ ORR $SCTLRSET, R0
+ ISB $SY
+ MSR R0, SCTLR_EL1
+ ISB $SY
+
+ B flushlocaltlb(SB)
+
+TEXT mmuenable<>(SB), 1, $-4
+ /* return to virtual */
+ ORR $KZERO, LR
+ MOV LR, -16(RSP)!
+
+ BL flushlocaltlb(SB)
+
+ /* memory attributes */
+#define MAIRINIT \
+ ( 0xFF << MA_MEM_WB*8 \
+ | 0x33 << MA_MEM_WT*8 \
+ | 0x44 << MA_MEM_UC*8 \
+ | 0x00 << MA_DEV_nGnRnE*8 \
+ | 0x04 << MA_DEV_nGnRE*8 \
+ | 0x08 << MA_DEV_nGRE*8 \
+ | 0x0C << MA_DEV_GRE*8 )
+ MOV $MAIRINIT, R1
+ MSR R1, MAIR_EL1
+ ISB $SY
+
+ /* translation control */
+#define TCRINIT \
+ /* TBI1 */ ( 0<<38 \
+ /* TBI0 */ | 0<<37 \
+ /* AS */ | 0<<36 \
+ /* TG1 */ | (((3<<16|1<<14|2<<12)>>PGSHIFT)&3)<<30 \
+ /* SH1 */ | SHARE_INNER<<28 \
+ /* ORGN1 */ | CACHE_WB<<26 \
+ /* IRGN1 */ | CACHE_WB<<24 \
+ /* EPD1 */ | 0<<23 \
+ /* A1 */ | 0<<22 \
+ /* T1SZ */ | (64-EVASHIFT)<<16 \
+ /* TG0 */ | (((1<<16|2<<14|0<<12)>>PGSHIFT)&3)<<14 \
+ /* SH0 */ | SHARE_INNER<<12 \
+ /* ORGN0 */ | CACHE_WB<<10 \
+ /* IRGN0 */ | CACHE_WB<<8 \
+ /* EPD0 */ | 0<<7 \
+ /* T0SZ */ | (64-EVASHIFT)<<0 )
+ MOV $TCRINIT, R1
+ MRS ID_AA64MMFR0_EL1, R2
+ ANDW $0x7, R2 // PARange
+ ADD R2<<32, R1 // IPS
+ MSR R1, TCR_EL1
+ ISB $SY
+
+ /* load the page tables */
+ MOV $(L1BOT-KZERO), R0
+ MOV $(L1TOP-KZERO), R1
+ ISB $SY
+ MSR R0, TTBR0_EL1
+ MSR R1, TTBR1_EL1
+ ISB $SY
+
+ /* enable MMU and caches */
+ MRS SCTLR_EL1, R1
+ ORR $SCTLRMMU, R1
+ ISB $SY
+ MSR R1, SCTLR_EL1
+ ISB $SY
+
+ MOV RSP, R1
+ ORR $KZERO, R1
+ MOV R1, RSP
+ MOV (RSP)16!, LR
+ B cacheiinv(SB)
+
+TEXT touser(SB), 1, $-4
+ MOVWU $0x10028, R1 // entry
+ MOVWU $0, R2 // psr
+ MSR R0, SP_EL0 // sp
+ MSR R1, ELR_EL1
+ MSR R2, SPSR_EL1
+ ERET
+
+TEXT cas(SB), 1, $-4
+TEXT cmpswap(SB), 1, $-4
+ MOVWU ov+8(FP), R1
+ MOVWU nv+16(FP), R2
+_cas1:
+ LDXRW (R0), R3
+ CMP R3, R1
+ BNE _cas0
+ STXRW R2, (R0), R4
+ CBNZ R4, _cas1
+ MOVW $1, R0
+ DMB $ISH
+ RETURN
+_cas0:
+ CLREX
+ MOVW $0, R0
+ RETURN
+
+TEXT tas(SB), 1, $-4
+TEXT _tas(SB), 1, $-4
+ MOVW $0xdeaddead, R2
+_tas1:
+ LDXRW (R0), R1
+ STXRW R2, (R0), R3
+ CBNZ R3, _tas1
+ MOVW R1, R0
+
+TEXT coherence(SB), 1, $-4
+ DMB $ISH
+ RETURN
+
+TEXT islo(SB), 1, $-4
+ MRS DAIF, R0
+ AND $(0x2<<6), R0
+ EOR $(0x2<<6), R0
+ RETURN
+
+TEXT splhi(SB), 1, $-4
+ MRS DAIF, R0
+ MSR $0x2, DAIFSet
+ RETURN
+
+TEXT splfhi(SB), 1, $-4
+ MRS DAIF, R0
+ MSR $0x3, DAIFSet
+ RETURN
+
+TEXT spllo(SB), 1, $-4
+ MSR $0x3, DAIFClr
+ RETURN
+
+TEXT splflo(SB), 1, $-4
+ MSR $0x1, DAIFClr
+ RETURN
+
+TEXT splx(SB), 1, $-4
+ MSR R0, DAIF
+ RETURN
+
+TEXT idlehands(SB), 1, $-4
+ DMB $ISH
+ MOVW nrdy(SB), R0
+ CBNZ R0, _ready
+ WFI
+_ready:
+ RETURN
+
+TEXT vcycles(SB), 1, $-4
+ MRS CNTVCT_EL0, R0
+ RETURN
+
+TEXT lcycles(SB), 1, $-4
+ MRS PMCCNTR_EL0, R0
+ RETURN
+
+TEXT setlabel(SB), 1, $-4
+ MOV LR, 8(R0)
+ MOV SP, R1
+ MOV R1, 0(R0)
+ MOVW $0, R0
+ RETURN
+
+TEXT gotolabel(SB), 1, $-4
+ MOV 8(R0), LR /* link */
+ MOV 0(R0), R1 /* sp */
+ MOV R1, SP
+ MOVW $1, R0
+ RETURN
+
+TEXT returnto(SB), 1, $-4
+ MOV R0, 0(SP)
+ RETURN
+
+TEXT getfar(SB), 1, $-4
+ MRS FAR_EL1, R0
+ RETURN
+
+TEXT setttbr(SB), 1, $-4
+ DSB $ISHST
+ MSR R0, TTBR0_EL1
+ DSB $ISH
+ ISB $SY
+ RETURN
+
+/*
+ * TLB maintenance operations.
+ * these broadcast to all cpu's in the cluser
+ * (inner sharable domain).
+ */
+TEXT flushasidva(SB), 1, $-4
+TEXT tlbivae1is(SB), 1, $-4
+ DSB $ISHST
+ TLBI R0, 0,8,3,1 /* VAE1IS */
+ DSB $ISH
+ ISB $SY
+ RETURN
+
+TEXT flushasidvall(SB), 1, $-4
+TEXT tlbivale1is(SB), 1, $-4
+ DSB $ISHST
+ TLBI R0, 0,8,3,5 /* VALE1IS */
+ DSB $ISH
+ ISB $SY
+ RETURN
+
+TEXT flushasid(SB), 1, $-4
+TEXT tlbiaside1is(SB), 1, $-4
+ DSB $ISHST
+ TLBI R0, 0,8,3,2 /* ASIDE1IS */
+ DSB $ISH
+ ISB $SY
+ RETURN
+
+TEXT flushtlb(SB), 1, $-4
+TEXT tlbivmalle1is(SB), 1, $-4
+ DSB $ISHST
+ TLBI R0, 0,8,3,0 /* VMALLE1IS */
+ DSB $ISH
+ ISB $SY
+ RETURN
+
+/*
+ * flush the tlb of this cpu. no broadcast.
+ */
+TEXT flushlocaltlb(SB), 1, $-4
+TEXT tlbivmalle1(SB), 1, $-4
+ DSB $NSHST
+ TLBI R0, 0,8,7,0 /* VMALLE1 */
+ DSB $NSH
+ ISB $SY
+ RETURN
+
+/*
+ * floating-point support.
+ */
+TEXT fpon(SB), 1, $-4
+ MOVW $(3<<20), R0
+ MSR R0, CPACR_EL1
+ ISB $SY
+ RETURN
+
+TEXT fpoff(SB), 1, $-4
+ MOVW $(0<<20), R0
+ MSR R0, CPACR_EL1
+ ISB $SY
+ RETURN
+
+TEXT fpsaveregs(SB), 1, $-4
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 0) /* MOV { V0, V1, V2, V3 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 4) /* MOV { V4, V5, V6, V7 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 8) /* MOV { V8, V9, V10,V11 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 12) /* MOV { V12,V13,V14,V15 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 16) /* MOV { V16,V17,V18,V19 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 20) /* MOV { V20,V21,V22,V23 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 24) /* MOV { V24,V25,V26,V27 }, (R0)64! */
+ WORD $(1<<30 | 3 << 26 | 2<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 28) /* MOV { V28,V29,V30,V31 }, (R0)64! */
+ RETURN
+
+TEXT fploadregs(SB), 1, $-4
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 0) /* MOV (R0)64!, { V0, V1, V2, V3 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 4) /* MOV (R0)64!, { V4, V5, V6, V7 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 8) /* MOV (R0)64!, { V8, V9, V10,V11 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 12) /* MOV (R0)64!, { V12,V13,V14,V15 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 16) /* MOV (R0)64!, { V16,V17,V18,V19 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 20) /* MOV (R0)64!, { V20,V21,V22,V23 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 24) /* MOV (R0)64!, { V24,V25,V26,V27 } */
+ WORD $(1<<30 | 3 << 26 | 3<<22 | 0x1F<<16 | 3<<10 | 0<<5 | 28) /* MOV (R0)64!, { V28,V29,V30,V31 } */
+ RETURN
+
+// syscall or trap from EL0
+TEXT vsys0(SB), 1, $-4
+ LSRW $26, R0, R17 // ec
+ CMPW $0x15, R17 // SVC trap?
+ BNE _itsatrap // nope.
+
+ MOVP R26, R27, 224(RSP)
+ MOVP R28, R29, 240(RSP)
+
+ MRS SP_EL0, R1
+ MRS ELR_EL1, R2
+ MRS SPSR_EL1, R3
+
+ MOV R0, 288(RSP) // type
+ MOV R1, 264(RSP) // sp
+ MOV R2, 272(RSP) // pc
+ MOV R3, 280(RSP) // psr
+
+ MOV $setSB(SB), R28
+ MRS TPIDR_EL1, R27
+ MOV 16(R27), R26
+
+ ADD $16, RSP, R0 // ureg
+ BL syscall(SB)
+
+TEXT forkret(SB), 1, $-4
+ MSR $0x3, DAIFSet // interrupts off
+
+ ADD $16, RSP, R0 // ureg
+
+ MOV 16(RSP), R0 // ret
+ MOV 264(RSP), R1 // sp
+ MOV 272(RSP), R2 // pc
+ MOV 280(RSP), R3 // psr
+
+ MSR R1, SP_EL0
+ MSR R2, ELR_EL1
+ MSR R3, SPSR_EL1
+
+ MOVP 224(RSP), R26, R27
+ MOVP 240(RSP), R28, R29
+
+ MOV 256(RSP), R30 // link
+
+ ADD $TRAPFRAMESIZE, RSP
+ ERET
+
+TEXT itsatrap<>(SB), 1, $-4
+_itsatrap:
+ MOVP R1, R2, 24(RSP)
+ MOVP R3, R4, 40(RSP)
+ MOVP R5, R6, 56(RSP)
+ MOVP R7, R8, 72(RSP)
+ MOVP R9, R10, 88(RSP)
+ MOVP R11, R12, 104(RSP)
+ MOVP R13, R14, 120(RSP)
+ MOVP R15, R16, 136(RSP)
+
+ MOVP R18, R19, 160(RSP)
+ MOVP R20, R21, 176(RSP)
+ MOVP R22, R23, 192(RSP)
+ MOVP R24, R25, 208(RSP)
+
+// trap/irq/fiq/serr from EL0
+TEXT vtrap0(SB), 1, $-4
+ MOVP R26, R27, 224(RSP)
+ MOVP R28, R29, 240(RSP)
+
+ MRS SP_EL0, R1
+ MRS ELR_EL1, R2
+ MRS SPSR_EL1, R3
+
+ MOV R0, 288(RSP) // type
+ MOV R1, 264(RSP) // sp
+ MOV R2, 272(RSP) // pc
+ MOV R3, 280(RSP) // psr
+
+ MOV $setSB(SB), R28
+ MRS TPIDR_EL1, R27
+ MOV 16(R27), R26
+
+ ADD $16, RSP, R0 // ureg
+ BL trap(SB)
+
+TEXT noteret(SB), 1, $-4
+ MSR $0x3, DAIFSet // interrupts off
+
+ ADD $16, RSP, R0 // ureg
+
+ MOV 264(RSP), R1 // sp
+ MOV 272(RSP), R2 // pc
+ MOV 280(RSP), R3 // psr
+
+ MSR R1, SP_EL0
+ MSR R2, ELR_EL1
+ MSR R3, SPSR_EL1
+
+ MOVP 224(RSP), R26, R27
+ MOVP 240(RSP), R28, R29
+
+_intrreturn:
+ MOVP 16(RSP), R0, R1
+ MOVP 32(RSP), R2, R3
+ MOVP 48(RSP), R4, R5
+ MOVP 64(RSP), R6, R7
+ MOVP 80(RSP), R8, R9
+ MOVP 96(RSP), R10, R11
+ MOVP 112(RSP), R12, R13
+ MOVP 128(RSP), R14, R15
+ MOVP 144(RSP), R16, R17
+ MOVP 160(RSP), R18, R19
+ MOVP 176(RSP), R20, R21
+ MOVP 192(RSP), R22, R23
+ MOVP 208(RSP), R24, R25
+
+ MOV 256(RSP), R30 // link
+
+ ADD $TRAPFRAMESIZE, RSP
+ ERET
+
+// irq/fiq/trap/serr from EL1
+TEXT vtrap1(SB), 1, $-4
+ MOV R29, 248(RSP) // special
+
+ ADD $TRAPFRAMESIZE, RSP, R1
+ MRS ELR_EL1, R2
+ MRS SPSR_EL1, R3
+
+ MOV R0, 288(RSP) // type
+ MOV R1, 264(RSP) // sp
+ MOV R2, 272(RSP) // pc
+ MOV R3, 280(RSP) // psr
+
+ ADD $16, RSP, R0 // ureg
+ BL trap(SB)
+
+ MSR $0x3, DAIFSet // interrupts off
+
+ MOV 272(RSP), R2 // pc
+ MOV 280(RSP), R3 // psr
+
+ MSR R2, ELR_EL1
+ MSR R3, SPSR_EL1
+
+ MOV 248(RSP), R29 // special
+ B _intrreturn
+
+// vector tables
+TEXT vsys(SB), 1, $-4
+ SUB $TRAPFRAMESIZE, RSP
+
+ MOV R0, 16(RSP)
+ MOV R30, 256(RSP) // link
+
+ MOV R17, 152(RSP) // temp
+
+ MRS ESR_EL1, R0 // type
+
+_vsyspatch:
+ B _vsyspatch // branch to vsys0() patched in
+
+TEXT vtrap(SB), 1, $-4
+ SUB $TRAPFRAMESIZE, RSP
+
+ MOVP R0, R1, 16(RSP)
+ MOVP R2, R3, 32(RSP)
+ MOVP R4, R5, 48(RSP)
+ MOVP R6, R7, 64(RSP)
+ MOVP R8, R9, 80(RSP)
+ MOVP R10, R11, 96(RSP)
+ MOVP R12, R13, 112(RSP)
+ MOVP R14, R15, 128(RSP)
+ MOVP R16, R17, 144(RSP)
+ MOVP R18, R19, 160(RSP)
+ MOVP R20, R21, 176(RSP)
+ MOVP R22, R23, 192(RSP)
+ MOVP R24, R25, 208(RSP)
+
+ MOV R30, 256(RSP) // link
+
+ MRS ESR_EL1, R0 // type
+
+_vtrappatch:
+ B _vtrappatch // branch to vtrapX() patched in
+
+TEXT virq(SB), 1, $-4
+ SUB $TRAPFRAMESIZE, RSP
+
+ MOVP R0, R1, 16(RSP)
+ MOVP R2, R3, 32(RSP)
+ MOVP R4, R5, 48(RSP)
+ MOVP R6, R7, 64(RSP)
+ MOVP R8, R9, 80(RSP)
+ MOVP R10, R11, 96(RSP)
+ MOVP R12, R13, 112(RSP)
+ MOVP R14, R15, 128(RSP)
+ MOVP R16, R17, 144(RSP)
+ MOVP R18, R19, 160(RSP)
+ MOVP R20, R21, 176(RSP)
+ MOVP R22, R23, 192(RSP)
+ MOVP R24, R25, 208(RSP)
+
+ MOV R30, 256(RSP) // link
+
+ MOV $(1<<32), R0 // type irq
+
+_virqpatch:
+ B _virqpatch // branch to vtrapX() patched in
+
+TEXT vfiq(SB), 1, $-4
+ SUB $TRAPFRAMESIZE, RSP
+
+ MOVP R0, R1, 16(RSP)
+ MOVP R2, R3, 32(RSP)
+ MOVP R4, R5, 48(RSP)
+ MOVP R6, R7, 64(RSP)
+ MOVP R8, R9, 80(RSP)
+ MOVP R10, R11, 96(RSP)
+ MOVP R12, R13, 112(RSP)
+ MOVP R14, R15, 128(RSP)
+ MOVP R16, R17, 144(RSP)
+ MOVP R18, R19, 160(RSP)
+ MOVP R20, R21, 176(RSP)
+ MOVP R22, R23, 192(RSP)
+ MOVP R24, R25, 208(RSP)
+
+ MOV R30, 256(RSP) // link
+ MOV $(2<<32), R0 // type fiq
+
+_vfiqpatch:
+ B _vfiqpatch // branch to vtrapX() patched in
+
+TEXT vserr(SB), 1, $-4
+ SUB $TRAPFRAMESIZE, RSP
+
+ MOVP R0, R1, 16(RSP)
+ MOVP R2, R3, 32(RSP)
+ MOVP R4, R5, 48(RSP)
+ MOVP R6, R7, 64(RSP)
+ MOVP R8, R9, 80(RSP)
+ MOVP R10, R11, 96(RSP)
+ MOVP R12, R13, 112(RSP)
+ MOVP R14, R15, 128(RSP)
+ MOVP R16, R17, 144(RSP)
+ MOVP R18, R19, 160(RSP)
+ MOVP R20, R21, 176(RSP)
+ MOVP R22, R23, 192(RSP)
+ MOVP R24, R25, 208(RSP)
+
+ MOV R30, 256(RSP) // link
+
+ MRS ESR_EL1, R0
+ ORR $(3<<32), R0 // type
+_vserrpatch:
+ B _vserrpatch // branch to vtrapX() patched in
+
+/* fault-proof memcpy */
+TEXT peek(SB), 1, $-4
+ MOV R0, R1
+ MOV dst+8(FP), R2
+ MOVWU len+16(FP), R0
+TEXT _peekinst(SB), 1, $-4
+_peekloop:
+ MOVBU (R1)1!, R3
+ MOVBU R3, (R2)1!
+ SUBS $1, R0
+ BNE _peekloop
+ RETURN
+
+TEXT smccall(SB), 1, $32
+ /* save extern registers */
+ MOVP R26, R27, (RSP)
+
+ /* R0 = Ureg */
+ MOV R0, R8
+
+ /* save ureg pointer */
+ MOV R8, 16(RSP)
+
+ MOVP 0(R8), R0, R1
+ MOVP 16(R8), R2, R3
+ MOVP 32(R8), R4, R5
+ MOVP 48(R8), R6, R7
+
+ SMC
+
+ /* restore ureg pointer */
+ MOV 16(RSP), R8
+
+ MOVP R0, R1, 0(R8)
+ MOVP R2, R3, 16(R8)
+
+ /* restore extern registers */
+ MOVP (RSP), R26, R27
+
+ RETURN
+
+
+
--- /dev/null
+++ b/sys/src/9/lx2k/main.c
@@ -1,0 +1,448 @@
+#include "u.h"
+#include "tos.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "pool.h"
+#include "io.h"
+#include "../arm64/sysreg.h"
+#include "ureg.h"
+
+#include "rebootcode.i"
+
+Conf conf;
+
+#define MAXCONF 64
+static char *confname[MAXCONF];
+static char *confval[MAXCONF];
+static int nconf = -1;
+
+void
+bootargsinit(void)
+{
+ int i, j, n;
+ char *cp, *line[MAXCONF], *p, *q;
+
+ /*
+ * parse configuration args from dos file plan9.ini
+ */
+ cp = BOOTARGS;
+ cp[BOOTARGSLEN-1] = 0;
+
+ /*
+ * Strip out '\r', change '\t' -> ' '.
+ */
+ p = cp;
+ for(q = cp; *q; q++){
+ if(*q == -1)
+ break;
+ if(*q == '\r')
+ continue;
+ if(*q == '\t')
+ *q = ' ';
+ *p++ = *q;
+ }
+ *p = 0;
+
+ n = getfields(cp, line, MAXCONF, 1, "\n");
+ if(n <= 0){
+ /* empty plan9.ini, no configuration passed */
+ return;
+ }
+
+ nconf = 0;
+ for(i = 0; i < n; i++){
+ if(*line[i] == '#')
+ continue;
+ cp = strchr(line[i], '=');
+ if(cp == nil)
+ continue;
+ *cp++ = '\0';
+ for(j = 0; j < nconf; j++){
+ if(cistrcmp(confname[j], line[i]) == 0)
+ break;
+ }
+ confname[j] = line[i];
+ confval[j] = cp;
+ if(j == nconf)
+ nconf++;
+ }
+}
+
+char*
+getconf(char *name)
+{
+ int i;
+
+ for(i = 0; i < nconf; i++)
+ if(cistrcmp(confname[i], name) == 0)
+ return confval[i];
+ return nil;
+}
+
+void
+setconfenv(void)
+{
+ int i;
+
+ if(nconf < 0){
+ /* use defaults when there was no configuration */
+ ksetenv("console", "0", 1);
+ return;
+ }
+
+ for(i = 0; i < nconf; i++){
+ if(confname[i][0] != '*')
+ ksetenv(confname[i], confval[i], 0);
+ ksetenv(confname[i], confval[i], 1);
+ }
+}
+
+void
+writeconf(void)
+{
+ char *p, *q;
+ int n;
+
+ p = getconfenv();
+ if(waserror()) {
+ free(p);
+ nexterror();
+ }
+
+ /* convert to name=value\n format */
+ for(q=p; *q; q++) {
+ q += strlen(q);
+ *q = '=';
+ q += strlen(q);
+ *q = '\n';
+ }
+ n = q - p + 1;
+ if(n >= BOOTARGSLEN)
+ error("kernel configuration too large");
+ memmove(BOOTARGS, p, n);
+ memset(BOOTARGS+n, 0, BOOTARGSLEN-n);
+ poperror();
+ free(p);
+}
+
+int
+isaconfig(char *, int, ISAConf *)
+{
+ return 0;
+}
+
+/*
+ * starting place for first process
+ */
+void
+init0(void)
+{
+ char buf[2*KNAMELEN], **sp;
+
+ chandevinit();
+
+ if(!waserror()){
+ snprint(buf, sizeof(buf), "%s %s", "ARM64", conffile);
+ ksetenv("terminal", buf, 0);
+ ksetenv("cputype", "arm64", 0);
+ if(cpuserver)
+ ksetenv("service", "cpu", 0);
+ else
+ ksetenv("service", "terminal", 0);
+ setconfenv();
+ poperror();
+ }
+ kproc("alarm", alarmkproc, 0);
+
+ sp = (char**)(USTKTOP-sizeof(Tos) - 8 - sizeof(sp[0])*4);
+ sp[3] = sp[2] = sp[1] = nil;
+ strcpy(sp[1] = (char*)&sp[4], "boot");
+ sp[0] = (void*)&sp[1];
+
+ splhi();
+ fpukexit(nil, nil);
+ touser((uintptr)sp);
+}
+
+void
+confinit(void)
+{
+ int userpcnt;
+ ulong kpages;
+ char *p;
+ int i;
+
+ conf.nmach = MAXMACH;
+ if(p = getconf("service")){
+ if(strcmp(p, "cpu") == 0)
+ cpuserver = 1;
+ else if(strcmp(p,"terminal") == 0)
+ cpuserver = 0;
+ }
+
+ if(p = getconf("*kernelpercent"))
+ userpcnt = 100 - strtol(p, 0, 0);
+ else
+ userpcnt = 0;
+
+ if(userpcnt < 10)
+ userpcnt = 60 + cpuserver*10;
+
+ conf.npage = 0;
+ for(i = 0; i < nelem(conf.mem); i++)
+ conf.npage += conf.mem[i].npage;
+
+ kpages = conf.npage - (conf.npage*userpcnt)/100;
+ if(kpages > ((uintptr)-VDRAM)/BY2PG)
+ kpages = ((uintptr)-VDRAM)/BY2PG;
+
+ conf.upages = conf.npage - kpages;
+ conf.ialloc = (kpages/2)*BY2PG;
+
+ /* set up other configuration parameters */
+ conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
+ if(cpuserver)
+ conf.nproc *= 3;
+ if(conf.nproc > 4000)
+ conf.nproc = 4000;
+ conf.nswap = conf.npage*3;
+ conf.nswppo = 4096;
+ conf.nimage = 200;
+
+ conf.copymode = conf.nmach > 1;
+
+ /*
+ * Guess how much is taken by the large permanent
+ * datastructures. Mntcache and Mntrpc are not accounted for.
+ */
+ kpages = conf.npage - conf.upages;
+ kpages *= BY2PG;
+ kpages -= conf.upages*sizeof(Page)
+ + conf.nproc*sizeof(Proc*)
+ + conf.nimage*sizeof(Image)
+ + conf.nswap
+ + conf.nswppo*sizeof(Page*);
+ mainmem->maxsize = kpages;
+ imagmem->maxsize = kpages;
+}
+
+void
+machinit(void)
+{
+ m->ticks = 1;
+ m->perf.period = 1;
+ active.machs[m->machno] = 1;
+}
+
+int
+mpidindex(uvlong mpid)
+{
+ switch(mpid&((1<<MPIDMASK)-1)){
+ case 0x1: return 1;
+ case 0x100: return 2;
+ case 0x101: return 3;
+ case 0x200: return 4;
+ case 0x201: return 5;
+ case 0x300: return 6;
+ case 0x301: return 7;
+ case 0x400: return 8;
+ case 0x401: return 9;
+ case 0x500: return 10;
+ case 0x501: return 11;
+ case 0x600: return 12;
+ case 0x601: return 13;
+ case 0x700: return 14;
+ case 0x701: return 15;
+ }
+ return 0;
+}
+
+static uvlong
+machmpid(int machno)
+{
+ static uvlong ids[] = {
+ 0x0, 0x1,
+ 0x100, 0x101,
+ 0x200, 0x201,
+ 0x300, 0x301,
+ 0x400, 0x401,
+ 0x500, 0x501,
+ 0x600, 0x601,
+ 0x700, 0x701,
+ };
+ return ids[machno];
+}
+
+void
+mpinit(void)
+{
+ extern void _start(void);
+ int i;
+
+ for(i = 1; i < conf.nmach; i++){
+ Ureg u = {0};
+
+ assert(mpidindex(machmpid(i)) == i);
+
+ MACHP(i)->machno = i;
+ cachedwbinvse(MACHP(i), MACHSIZE);
+
+ u.r0 = 0x84000003; /* CPU_ON */
+ u.r1 = machmpid(i);
+ u.r2 = PADDR(_start);
+ u.r3 = i;
+ smccall(&u);
+ }
+ synccycles();
+}
+
+void
+cpuidprint(void)
+{
+ iprint("cpu%d: %dMHz ARM Cortex A72\n", m->machno, m->cpumhz);
+}
+
+void
+main(void)
+{
+ machinit();
+ if(m->machno){
+ trapinit();
+ fpuinit();
+ intrinit();
+ clockinit();
+ cpuidprint();
+ synccycles();
+ timersinit();
+ mmu1init();
+ m->ticks = MACHP(0)->ticks;
+ schedinit();
+ return;
+ }
+ quotefmtinstall();
+ bootargsinit();
+ meminit();
+ confinit();
+ xinit();
+ uartconsinit();
+ printinit();
+ print("\nPlan 9\n");
+ trapinit();
+ fpuinit();
+ intrinit();
+ clockinit();
+ cpuidprint();
+ timersinit();
+ pageinit();
+ procinit0();
+ initseg();
+ links();
+ chandevreset();
+ userinit();
+ mpinit();
+ mmu1init();
+ schedinit();
+}
+
+void
+exit(int)
+{
+ Ureg u = { .r0 = 0x84000002 }; /* CPU_OFF */
+
+ cpushutdown();
+ splfhi();
+
+ if(m->machno == 0){
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+
+ u.r0 = 0x84000009; /* SYSTEM RESET */
+ }
+ smccall(&u);
+}
+
+static void
+rebootjump(void *entry, void *code, ulong size)
+{
+ void (*f)(void*, void*, ulong);
+
+ intrcpushutdown();
+
+ /* redo identity map */
+ setttbr(PADDR(L1BOT));
+
+ /* setup reboot trampoline function */
+ f = (void*)REBOOTADDR;
+ memmove(f, rebootcode, sizeof(rebootcode));
+
+ cachedwbinvse(f, sizeof(rebootcode));
+ cacheiinvse(f, sizeof(rebootcode));
+
+ (*f)(entry, code, size);
+
+ for(;;);
+}
+
+void
+reboot(void*, void *code, ulong size)
+{
+ writeconf();
+ while(m->machno != 0){
+ procwired(up, 0);
+ sched();
+ }
+
+ cpushutdown();
+ delay(2000);
+
+ splfhi();
+
+ /* turn off buffered serial console */
+ serialoq = nil;
+
+ /* shutdown devices */
+ chandevshutdown();
+
+ /* stop the clock */
+ clockshutdown();
+ intrsoff();
+
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+
+ /* off we go - never to return */
+ rebootjump((void*)(KTZERO-KZERO), code, size);
+}
+
+void
+dmaflush(int clean, void *p, ulong len)
+{
+ uintptr s = (uintptr)p;
+ uintptr e = (uintptr)p + len;
+
+ if(clean){
+ s &= ~(BLOCKALIGN-1);
+ e += BLOCKALIGN-1;
+ e &= ~(BLOCKALIGN-1);
+ cachedwbse((void*)s, e - s);
+ return;
+ }
+ if(s & BLOCKALIGN-1){
+ s &= ~(BLOCKALIGN-1);
+ cachedwbinvse((void*)s, BLOCKALIGN);
+ s += BLOCKALIGN;
+ }
+ if(e & BLOCKALIGN-1){
+ e &= ~(BLOCKALIGN-1);
+ if(e < s)
+ return;
+ cachedwbinvse((void*)e, BLOCKALIGN);
+ }
+ if(s < e)
+ cachedinvse((void*)s, e - s);
+}
--- /dev/null
+++ b/sys/src/9/lx2k/mem.c
@@ -1,0 +1,85 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+#define INITMAP (ROUND((uintptr)end + BY2PG, PGLSZ(1))-KZERO)
+
+/*
+ * Create initial identity map in top-level page table
+ * (L1BOT) for TTBR0. This page table is only used until
+ * mmu1init() loads m->mmutop.
+ */
+void
+mmuidmap(uintptr *l1bot)
+{
+ uintptr pa, pe, attr;
+
+ /* VDRAM */
+ attr = PTEWRITE | PTEAF | PTEKERNEL | PTEUXN | PTESH(SHARE_INNER);
+ pe = -KZERO;
+ for(pa = VDRAM - KZERO; pa < pe; pa += PGLSZ(PTLEVELS-1))
+ l1bot[PTLX(pa, PTLEVELS-1)] = pa | PTEVALID | PTEBLOCK | attr;
+}
+
+/*
+ * Create initial shared kernel page table (L1) for TTBR1.
+ * This page table coveres the INITMAP and VIRTIO,
+ * and later we fill the ram mappings in meminit().
+ */
+void
+mmu0init(uintptr *l1)
+{
+ uintptr va, pa, pe, attr;
+
+ /* DRAM - INITMAP */
+ attr = PTEWRITE | PTEAF | PTEKERNEL | PTEUXN | PTESH(SHARE_INNER);
+ pe = INITMAP;
+ for(pa = VDRAM - KZERO, va = VDRAM; pa < pe; pa += PGLSZ(1), va += PGLSZ(1))
+ l1[PTL1X(va, 1)] = pa | PTEVALID | PTEBLOCK | attr;
+
+ /* VIRTIO */
+ attr = PTEWRITE | PTEAF | PTEKERNEL | PTEUXN | PTEPXN | PTESH(SHARE_OUTER) | PTEDEVICE;
+ pe = PHYSIOEND;
+ for(pa = PHYSIO, va = VIRTIO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1)){
+ if(((pa|va) & PGLSZ(1)-1) != 0){
+ l1[PTL1X(va, 1)] = (uintptr)l1 | PTEVALID | PTETABLE;
+ for(; pa < pe && ((va|pa) & PGLSZ(1)-1) != 0; pa += PGLSZ(0), va += PGLSZ(0)){
+ assert(l1[PTLX(va, 0)] == 0);
+ l1[PTLX(va, 0)] = pa | PTEVALID | PTEPAGE | attr;
+ }
+ break;
+ }
+ l1[PTL1X(va, 1)] = pa | PTEVALID | PTEBLOCK | attr;
+ }
+
+ if(PTLEVELS > 2)
+ for(va = KSEG0; va != 0; va += PGLSZ(2))
+ l1[PTL1X(va, 2)] = (uintptr)&l1[L1TABLEX(va, 1)] | PTEVALID | PTETABLE;
+
+ if(PTLEVELS > 3)
+ for(va = KSEG0; va != 0; va += PGLSZ(3))
+ l1[PTL1X(va, 3)] = (uintptr)&l1[L1TABLEX(va, 2)] | PTEVALID | PTETABLE;
+}
+
+void
+meminit(void)
+{
+ char *p;
+
+ /* GPP DRAM Region #1 */
+ conf.mem[0].base = PGROUND((uintptr)end - KZERO);
+ conf.mem[0].limit = 0x100000000ULL;
+
+ kmapram(conf.mem[0].base, conf.mem[0].limit);
+
+ conf.mem[0].npage = (conf.mem[0].limit - conf.mem[0].base)/BY2PG;
+
+ if(p = getconf("*maxmem")){
+ /* GPP DRAM Region #2 */
+ conf.mem[1].base = 0x2080000000ULL;
+ conf.mem[1].limit = strtoull(p, 0, 0);
+ conf.mem[1].npage = (conf.mem[1].limit - conf.mem[1].base)/BY2PG;
+ }
+}
--- /dev/null
+++ b/sys/src/9/lx2k/mem.h
@@ -1,0 +1,148 @@
+/*
+ * Memory and machine-specific definitions. Used in C and assembler.
+ */
+#define KiB 1024u /* Kibi 0x0000000000000400 */
+#define MiB 1048576u /* Mebi 0x0000000000100000 */
+#define GiB 1073741824u /* Gibi 000000000040000000 */
+
+/*
+ * Sizes:
+ * L0 L1 L2 L3
+ * 4K 2M 1G 512G
+ * 16K 32M 64G 128T
+ * 64K 512M 4T -
+ */
+#define PGSHIFT 12 /* log(BY2PG) */
+#define BY2PG (1ULL<<PGSHIFT) /* bytes per page */
+#define ROUND(s, sz) (((s)+(sz-1))&~(sz-1))
+#define PGROUND(s) ROUND(s, BY2PG)
+
+/* effective virtual address space */
+#define EVASHIFT 34
+#define EVAMASK ((1ULL<<EVASHIFT)-1)
+
+#define PTSHIFT (PGSHIFT-3)
+#define PTLEVELS (((EVASHIFT-PGSHIFT)+PTSHIFT-1)/PTSHIFT)
+#define PTLX(v, l) ((((v) & EVAMASK) >> (PGSHIFT + (l)*PTSHIFT)) & ((1 << PTSHIFT)-1))
+#define PGLSZ(l) (1ULL << (PGSHIFT + (l)*PTSHIFT))
+
+#define PTL1X(v, l) (L1TABLEX(v, l) | PTLX(v, l))
+#define L1TABLEX(v, l) (L1TABLE(v, l) << PTSHIFT)
+#define L1TABLES ((-KSEG0+PGLSZ(2)-1)/PGLSZ(2))
+#define L1TABLE(v, l) (L1TABLES - ((PTLX(v, 2) % L1TABLES) >> (((l)-1)*PTSHIFT)) + (l)-1)
+#define L1TOPSIZE (1ULL << (EVASHIFT - PTLEVELS*PTSHIFT))
+
+#define MPIDMASK 11
+#define MAXMACH 1 /* max # cpus system can run */
+#define MACHSIZE (8*KiB)
+
+#define KSTACK (8*KiB)
+#define STACKALIGN(sp) ((sp) & ~7) /* bug: assure with alloc */
+#define TRAPFRAMESIZE (38*8)
+
+#define VDRAM (0xFFFFFFFFC0000000ULL) /* 0x80000000 - 0xc0000000 */
+#define KTZERO (VDRAM + 0x100000) /* 0x80100000 - kernel text start */
+
+#define PHYSIO (0x1000000ULL)
+#define PHYSIOEND (0x10000000ULL)
+
+#define VIRTIO (0xFFFFFFFFB0000000ULL)
+
+#define KZERO (0xFFFFFFFF40000000ULL) /* 0x00000000 - kernel address space */
+
+#define VMAP (0xFFFFFFFF00000000ULL) /* 0x00000000 - 0x40000000 */
+
+#define KMAPEND (0xFFFFFFFF00000000ULL) /* 0x140000000 */
+#define KMAP (0xFFFFFFFE00000000ULL) /* 0x40000000 */
+
+#define KSEG0 (0xFFFFFFFE00000000ULL)
+
+/* temporary identity map for TTBR0 (using only top-level) */
+#define L1BOT ((L1-L1TOPSIZE)&-BY2PG)
+
+/* shared kernel page table for TTBR1 */
+#define L1 (L1TOP-L1SIZE)
+#define L1SIZE ((L1TABLES+PTLEVELS-2)*BY2PG)
+#define L1TOP ((MACHADDR(MAXMACH-1)-L1TOPSIZE)&-BY2PG)
+
+#define MACHADDR(n) (KTZERO-((n)+1)*MACHSIZE)
+
+#define CONFADDR (VDRAM + 0x10000) /* 0x40010000 */
+
+#define BOOTARGS ((char*)CONFADDR)
+#define BOOTARGSLEN 0x10000
+
+#define REBOOTADDR (VDRAM-KZERO + 0x20000) /* 0x40020000 */
+
+#define UZERO 0ULL /* user segment */
+#define UTZERO (UZERO+0x10000) /* user text start */
+#define USTKTOP ((EVAMASK>>1)-0xFFFF) /* user segment end +1 */
+#define USTKSIZE (16*1024*1024) /* user stack size */
+
+#define BLOCKALIGN 64 /* only used in allocb.c */
+
+/*
+ * Sizes
+ */
+#define BI2BY 8 /* bits per byte */
+#define BY2SE 4
+#define BY2WD 8
+#define BY2V 8 /* only used in xalloc.c */
+
+#define PTEMAPMEM (1024*1024)
+#define PTEPERTAB (PTEMAPMEM/BY2PG)
+#define SEGMAPSIZE 8192
+#define SSEGMAPSIZE 16
+#define PPN(x) ((x)&~(BY2PG-1))
+
+#define SHARE_NONE 0
+#define SHARE_OUTER 2
+#define SHARE_INNER 3
+
+#define CACHE_UC 0
+#define CACHE_WB 1
+#define CACHE_WT 2
+#define CACHE_WB_NA 3
+
+#define MA_MEM_WB 0
+#define MA_MEM_WT 1
+#define MA_MEM_UC 2
+#define MA_DEV_nGnRnE 3
+#define MA_DEV_nGnRE 4
+#define MA_DEV_nGRE 5
+#define MA_DEV_GRE 6
+
+#define PTEVALID 1
+#define PTEBLOCK 0
+#define PTETABLE 2
+#define PTEPAGE 2
+
+#define PTEMA(x) ((x)<<2)
+#define PTEAP(x) ((x)<<6)
+#define PTESH(x) ((x)<<8)
+
+#define PTEAF (1<<10)
+#define PTENG (1<<11)
+#define PTEPXN (1ULL<<53)
+#define PTEUXN (1ULL<<54)
+
+#define PTEKERNEL PTEAP(0)
+#define PTEUSER PTEAP(1)
+#define PTEWRITE PTEAP(0)
+#define PTERONLY PTEAP(2)
+#define PTENOEXEC (PTEPXN|PTEUXN)
+
+#define PTECACHED PTEMA(MA_MEM_WB)
+#define PTEWT PTEMA(MA_MEM_WT)
+#define PTEUNCACHED PTEMA(MA_MEM_UC)
+#define PTEDEVICE PTEMA(MA_DEV_nGnRE)
+
+/*
+ * Physical machine information from here on.
+ * PHYS addresses as seen from the arm cpu.
+ * BUS addresses as seen from peripherals
+ */
+#define PHYSDRAM 0
+
+#define MIN(a, b) ((a) < (b)? (a): (b))
+#define MAX(a, b) ((a) > (b)? (a): (b))
--- /dev/null
+++ b/sys/src/9/lx2k/mkfile
@@ -1,0 +1,115 @@
+CONF=honeycomb
+CONFLIST=honeycomb
+
+kzero=0xffffffff40000000
+loadaddr=0xffffffffc0100000
+
+objtype=arm64
+</$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\
+ page.$O\
+ parse.$O\
+ pgrp.$O\
+ portclock.$O\
+ print.$O\
+ proc.$O\
+ qio.$O\
+ qlock.$O\
+ rdb.$O\
+ rebootcmd.$O\
+ segment.$O\
+ syscallfmt.$O\
+ sysfile.$O\
+ sysproc.$O\
+ taslock.$O\
+ tod.$O\
+ xalloc.$O\
+ userinit.$O\
+
+OBJ=\
+ l.$O\
+ cache.v8.$O\
+ clock.$O\
+ fpu.$O\
+ main.$O\
+ mmu.$O\
+ mem.$O\
+ sysreg.$O\
+ random.$O\
+ trap.$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\
+# /$objtype/lib/libdtracy.a\
+
+9:V: $p$CONF $p$CONF.u
+
+$p$CONF.u:D: $p$CONF
+ aux/aout2uimage -Z$kzero $p$CONF
+
+$p$CONF:D: $OBJ $CONF.$O $LIB
+ $LD -o $target -T$loadaddr -l $prereq
+ size $target
+
+$OBJ: $HFILES
+
+install:V: /$objtype/$p$CONF
+
+/$objtype/$p$CONF:D: $p$CONF $p$CONF.u
+ cp -x $p$CONF $p$CONF.u /$objtype/
+
+ARM64FILES=`{../port/mkfilelist ../arm64}
+^($ARM64FILES)\.$O:R: '../arm64/\1.c'
+ $CC $CFLAGS -I. -. ../arm64/$stem1.c
+
+cache.v8.$O: ../arm64/cache.v8.s
+ $AS $AFLAGS -I. -. ../arm64/cache.v8.s
+init9.$O: ../arm64/init9.s
+ $AS $AFLAGS -I. -. ../arm64/init9.s
+rebootcode.$O: ../arm64/rebootcode.s
+ $AS $AFLAGS -I. -. ../arm64/rebootcode.s
+
+<../boot/bootmkfile
+<../port/portmkfile
+<|../port/mkbootrules $CONF
+
+main.$O: rebootcode.i
+
+pcilx2k.$O: ../port/pci.h
+usbxhcilx2k.$O: ../port/usbxhci.h
+usdhc.$O: ../port/sd.h
+
+l.$O main.$O clock.$O gic.$O cache.v8.$O fpu.$O trap.$O rebootcode.$O: ../arm64/sysreg.h
+
+initcode.out: init9.$O initcode.$O /$objtype/lib/libc.a
+ $LD -l -R1 -s -o $target $prereq
+
+rebootcode.out: rebootcode.$O cache.v8.$O
+ $LD -l -H6 -R1 -T0x80020000 -s -o $target $prereq
+
+$CONF.clean:
+ rm -rf $p$CONF $p$CONF.u errstr.h $CONF.c boot$CONF.c
--- /dev/null
+++ b/sys/src/9/lx2k/pcilx2k.c
@@ -1,0 +1,372 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/pci.h"
+
+typedef struct Intvec Intvec;
+struct Intvec
+{
+ Pcidev *p;
+ void (*f)(Ureg*, void*);
+ void *a;
+};
+
+typedef struct Ctlr Ctlr;
+struct Ctlr
+{
+ uvlong mem_base;
+ uvlong mem_size;
+ uvlong cfg_base;
+ uvlong cfg_size;
+ uvlong io_base;
+ uvlong io_size;
+
+ int bno, ubn;
+ int irq;
+
+ u32int *dbi;
+ u32int *cfg;
+ Pcidev *bridge;
+
+ Lock;
+ Intvec vec[32];
+};
+
+static Ctlr ctlrs[2] = {
+ {
+ 0x9040000000ULL, 0x40000000,
+ 0x9000000000ULL, 0x2000,
+ 0x9000020000ULL, 0x10000,
+ 0, 127, IRQpci3,
+ (u32int*)(VIRTIO + 0x2600000),
+ },
+ {
+ 0xa040000000ULL, 0x40000000,
+ 0xa000000000ULL, 0x2000,
+ 0xa000020000ULL, 0x10000,
+ 128, 255, IRQpci5,
+ (u32int*)(VIRTIO + 0x2800000),
+ },
+};
+
+enum {
+ IATU_MAX = 8,
+ IATU_INBOUND = 1<<31,
+
+ IATU_OFFSET = 0x900/4,
+
+ IATU_REGION_INDEX = 0x00/4,
+
+ IATU_REGION_CTRL_1 = 0x04/4,
+ CTRL_1_INCREASE_REGION_SIZ = 1<<13,
+
+ CTRL_1_TYPE_SHIFT = 0,
+ CTRL_1_TYPE_MASK = 0x1F<<CTRL_1_TYPE_SHIFT,
+ CTRL_1_TYPE_MEM = 0x0<<CTRL_1_TYPE_SHIFT,
+ CTRL_1_TYPE_IO = 0x2<<CTRL_1_TYPE_SHIFT,
+ CTRL_1_TYPE_CFG0 = 0x4<<CTRL_1_TYPE_SHIFT,
+ CTRL_1_TYPE_CFG1 = 0x5<<CTRL_1_TYPE_SHIFT,
+
+ IATU_REGION_CTRL_2 = 0x08/4,
+ CTRL_2_REGION_EN = 1<<31,
+
+ IATU_LWR_BASE_ADDR = 0x0C/4,
+ IATU_UPPER_BASE_ADDR = 0x10/4,
+ IATU_LWR_LIMIT_ADDR = 0x14/4,
+ IATU_LWR_TARGET_ADDR = 0x18/4,
+ IATU_UPPER_TARGET_ADDR = 0x1C/4,
+};
+
+/* disable all iATU's */
+static void
+iatuinit(Ctlr *ctlr)
+{
+ u32int *reg = &ctlr->dbi[IATU_OFFSET];
+ int index;
+
+ for(index=0; index < IATU_MAX; index++){
+ reg[IATU_REGION_INDEX] = index;
+ reg[IATU_REGION_CTRL_2] &= ~CTRL_2_REGION_EN;
+
+ reg[IATU_REGION_INDEX] |= IATU_INBOUND;
+ reg[IATU_REGION_CTRL_2] &= ~CTRL_2_REGION_EN;
+ }
+}
+
+static void
+iatucfg(Ctlr *ctlr, int index, u32int type, uvlong target, uvlong base, uvlong size)
+{
+ uvlong limit = base + size - 1;
+ u32int *reg = &ctlr->dbi[IATU_OFFSET];
+
+ assert(size > 0);
+ assert(index < IATU_MAX);
+ assert((index & IATU_INBOUND) == 0);
+
+ reg[IATU_REGION_INDEX] = index;
+ reg[IATU_REGION_CTRL_2] &= ~CTRL_2_REGION_EN;
+
+ reg[IATU_LWR_BASE_ADDR] = base;
+ reg[IATU_UPPER_BASE_ADDR] = base >> 32;
+ reg[IATU_LWR_LIMIT_ADDR] = limit;
+ reg[IATU_LWR_TARGET_ADDR] = target;
+ reg[IATU_UPPER_TARGET_ADDR] = target >> 32;
+
+ type &= CTRL_1_TYPE_MASK;
+ if(((size-1)>>32) != 0)
+ type |= CTRL_1_INCREASE_REGION_SIZ;
+
+ reg[IATU_REGION_CTRL_1] = type;
+ reg[IATU_REGION_CTRL_2] = CTRL_2_REGION_EN;
+
+ while((reg[IATU_REGION_CTRL_2] & CTRL_2_REGION_EN) == 0)
+ microdelay(10);
+}
+
+static Ctlr*
+bus2ctlr(int bno)
+{
+ Ctlr *ctlr;
+
+ for(ctlr = ctlrs; ctlr < &ctlrs[nelem(ctlrs)]; ctlr++)
+ if(bno >= ctlr->bno && bno <= ctlr->ubn)
+ return ctlr;
+ return nil;
+}
+
+static void*
+cfgaddr(int tbdf, int rno)
+{
+ Ctlr *ctlr;
+
+ ctlr = bus2ctlr(BUSBNO(tbdf));
+ if(ctlr == nil)
+ return nil;
+
+ if(pciparentdev == nil){
+ if(BUSDNO(tbdf) != 0 || BUSFNO(tbdf) != 0)
+ return nil;
+ return (uchar*)ctlr->dbi + rno;
+ }
+
+ iatucfg(ctlr, 0,
+ pciparentdev->parent==nil? CTRL_1_TYPE_CFG0: CTRL_1_TYPE_CFG1,
+ BUSBNO(tbdf)<<20 | BUSDNO(tbdf)<<15 | BUSFNO(tbdf)<<12,
+ ctlr->cfg_base, ctlr->cfg_size);
+
+ return (uchar*)ctlr->cfg + rno;
+}
+
+int
+pcicfgrw32(int tbdf, int rno, int data, int read)
+{
+ u32int *p;
+
+ if((p = cfgaddr(tbdf, rno & ~3)) != nil){
+ if(read)
+ data = *p;
+ else
+ *p = data;
+ } else {
+ data = -1;
+ }
+ return data;
+}
+
+int
+pcicfgrw16(int tbdf, int rno, int data, int read)
+{
+ u16int *p;
+
+ if((p = cfgaddr(tbdf, rno & ~1)) != nil){
+ if(read)
+ data = *p;
+ else
+ *p = data;
+ } else {
+ data = -1;
+ }
+ return data;
+}
+
+int
+pcicfgrw8(int tbdf, int rno, int data, int read)
+{
+ u8int *p;
+
+ if((p = cfgaddr(tbdf, rno)) != nil){
+ if(read)
+ data = *p;
+ else
+ *p = data;
+ } else {
+ data = -1;
+ }
+ return data;
+}
+
+enum {
+ MISC_CONTROL_1 = 0x8BC/4,
+ DBI_RO_WR_EN = 1<<0,
+};
+
+static void
+pciinterrupt(Ureg *ureg, void *arg)
+{
+ Ctlr *ctlr = arg;
+ Intvec *vec;
+
+ ilock(ctlr);
+ for(vec = ctlr->vec; vec < &ctlr->vec[nelem(ctlr->vec)]; vec++){
+ if(vec->f != nil)
+ (*vec->f)(ureg, vec->a);
+ }
+ iunlock(ctlr);
+}
+
+static void
+pciintrinit(Ctlr *ctlr)
+{
+
+ intrenable(ctlr->irq+0, pciinterrupt, ctlr, BUSUNKNOWN, "pci");
+ intrenable(ctlr->irq+1, pciinterrupt, ctlr, BUSUNKNOWN, "pci");
+ intrenable(ctlr->irq+2, pciinterrupt, ctlr, BUSUNKNOWN, "pci");
+ intrenable(ctlr->irq+3, pciinterrupt, ctlr, BUSUNKNOWN, "pci");
+}
+
+void
+pciintrenable(int tbdf, void (*f)(Ureg*, void*), void *a)
+{
+ Ctlr *ctlr;
+ Intvec *vec;
+ Pcidev *p;
+
+ ctlr = bus2ctlr(BUSBNO(tbdf));
+ if(ctlr == nil){
+ print("pciintrenable: %T: unknown controller\n", tbdf);
+ return;
+ }
+
+ if((p = pcimatchtbdf(tbdf)) == nil){
+ print("pciintrenable: %T: unknown device\n", tbdf);
+ return;
+ }
+ if(pcimsidisable(p) < 0){
+ print("pciintrenable: %T: device doesnt support vec\n", tbdf);
+ return;
+ }
+
+ ilock(ctlr);
+ for(vec = ctlr->vec; vec < &ctlr->vec[nelem(ctlr->vec)]; vec++){
+ if(vec->p == p){
+ vec->p = nil;
+ break;
+ }
+ }
+ for(vec = ctlr->vec; vec < &ctlr->vec[nelem(ctlr->vec)]; vec++){
+ if(vec->p == nil){
+ vec->p = p;
+ vec->a = a;
+ vec->f = f;
+ break;
+ }
+ }
+ iunlock(ctlr);
+
+ if(vec >= &ctlr->vec[nelem(ctlr->vec)]){
+ print("pciintrenable: %T: out of isr slots\n", tbdf);
+ return;
+ }
+}
+
+void
+pciintrdisable(int tbdf, void (*f)(Ureg*, void*), void *a)
+{
+ Ctlr *ctlr;
+ Intvec *vec;
+
+ ctlr = bus2ctlr(BUSBNO(tbdf));
+ if(ctlr == nil){
+ print("pciintrenable: %T: unknown controller\n", tbdf);
+ return;
+ }
+
+ ilock(ctlr);
+ for(vec = ctlr->vec; vec < &ctlr->vec[nelem(ctlr->vec)]; vec++){
+ if(vec->p == nil)
+ continue;
+ if(vec->p->tbdf == tbdf && vec->f == f && vec->a == a){
+ vec->f = nil;
+ vec->a = nil;
+ vec->p = nil;
+ break;
+ }
+ }
+ iunlock(ctlr);
+}
+
+static void
+rootinit(Ctlr *ctlr)
+{
+ uvlong base;
+ ulong ioa;
+
+ iatuinit(ctlr);
+
+ ctlr->cfg = vmap(ctlr->cfg_base, ctlr->cfg_size);
+ if(ctlr->cfg == nil)
+ return;
+
+ ctlr->dbi[MISC_CONTROL_1] |= DBI_RO_WR_EN;
+
+ /* bus number */
+ ctlr->dbi[PciPBN/4] &= ~0xFFFFFF;
+ ctlr->dbi[PciPBN/4] |= ctlr->bno | (ctlr->bno+1)<<8 | ctlr->ubn<<16;
+
+ /* command */
+ ctlr->dbi[PciPCR/4] &= ~0xFFFF;
+ ctlr->dbi[PciPCR/4] |= IOen | MEMen | MASen | SErrEn;
+
+ /* device class/subclass */
+ ctlr->dbi[PciRID/4] &= ~0xFFFF0000;
+ ctlr->dbi[PciRID/4] |= 0x06040000;
+
+ ctlr->dbi[PciBAR0/4] = 0;
+ ctlr->dbi[PciBAR1/4] = 0;
+
+ ctlr->dbi[MISC_CONTROL_1] &= ~DBI_RO_WR_EN;
+
+ ctlr->ubn = pciscan(ctlr->bno, &ctlr->bridge, nil);
+ if(ctlr->bridge == nil || ctlr->bridge->bridge == nil)
+ return;
+
+ pciintrinit(ctlr);
+
+ iatucfg(ctlr, 1, CTRL_1_TYPE_IO, ctlr->io_base, ctlr->io_base, ctlr->io_size);
+ iatucfg(ctlr, 2, CTRL_1_TYPE_MEM, ctlr->mem_base, ctlr->mem_base, ctlr->mem_size);
+
+ ioa = ctlr->io_base;
+ base = ctlr->mem_base;
+ pcibusmap(ctlr->bridge, &base, &ioa, 1);
+
+ pcihinv(ctlr->bridge);
+}
+
+static void
+pcicfginit(void)
+{
+ int i;
+
+ fmtinstall('T', tbdffmt);
+ for(i = 0; i < nelem(ctlrs); i++)
+ rootinit(&ctlrs[i]);
+}
+
+void
+pcilx2klink(void)
+{
+ pcicfginit();
+}
--- /dev/null
+++ b/sys/src/9/lx2k/uartlx2k.c
@@ -1,0 +1,366 @@
+/*
+ * PL011 UART from Miller's BCM2835 driver
+ */
+
+#include "u.h"
+#include "../port/lib.h"
+#include "../port/error.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+enum {
+ DR = 0x00>>2,
+ RSRECR = 0x04>>2,
+ FR = 0x18>>2,
+ TXFE = 1<<7,
+ RXFF = 1<<6,
+ TXFF = 1<<5,
+ RXFE = 1<<4,
+ BUSY = 1<<3,
+
+ ILPR = 0x20>>2,
+ IBRD = 0x24>>2,
+ FBRD = 0x28>>2,
+ LCRH = 0x2c>>2,
+ WLENM = 3<<5,
+ WLEN8 = 3<<5,
+ WLEN7 = 2<<5,
+ WLEN6 = 1<<5,
+ WLEN5 = 0<<5,
+ FEN = 1<<4, /* fifo enable */
+ STP2 = 1<<3, /* 2 stop bits */
+ EPS = 1<<2, /* even parity select */
+ PEN = 1<<1, /* parity enabled */
+ BRK = 1<<0, /* send break */
+
+ CR = 0x30>>2,
+ CTSEN = 1<<15,
+ RTSEN = 1<<14,
+ RTS = 1<<11,
+ RXE = 1<<9,
+ TXE = 1<<8,
+ LBE = 1<<7,
+ UARTEN = 1<<0,
+
+ IFLS = 0x34>>2,
+ IMSC = 0x38>>2,
+ TXIM = 1<<5,
+ RXIM = 1<<4,
+
+ RIS = 0x3c>>2,
+ MIS = 0x40>>2,
+ ICR = 0x44>>2,
+ DMACR = 0x48>>2,
+ ITCR = 0x80>>2,
+ ITIP = 0x84>>2,
+ ITOP = 0x88>>2,
+ TDR = 0x8c>>2,
+};
+
+extern PhysUart lx2kphysuart;
+
+static Uart lx2kuart = {
+ .regs = (u32int*)(VIRTIO+0x11c0000ULL),
+ .name = "uart0",
+ .freq = 24*Mhz,
+ .baud = 115200,
+ .phys = &lx2kphysuart,
+};
+
+static Uart*
+pnp(void)
+{
+ return &lx2kuart;
+}
+
+static void
+interrupt(Ureg*, void *arg)
+{
+ Uart *uart = arg;
+ u32int *reg = (u32int*)uart->regs;
+
+ coherence();
+ while((reg[FR] & RXFE) == 0)
+ uartrecv(uart, reg[DR] & 0xFF);
+ if((reg[FR] & TXFF) == 0)
+ uartkick(uart);
+ reg[ICR] = 1<<5 | 1<<6 | 1<<7 | 1<<8 | 1<<9 | 1<<10;
+ coherence();
+}
+
+static void
+disable(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ /* disable interrupt */
+ reg[IMSC] = 0;
+ coherence();
+
+ /* clear interrupt */
+ reg[ICR] = 1<<5 | 1<<6 | 1<<7 | 1<<8 | 1<<9 | 1<<10;
+ coherence();
+
+ /* wait for last transmission to complete */
+ while((reg[FR] & BUSY) != 0)
+ delay(1);
+
+ /* disable uart */
+ reg[CR] = 0;
+ coherence();
+
+ /* flush rx fifo */
+ reg[LCRH] &= ~FEN;
+ coherence();
+}
+
+static void
+uartoff(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+ u32int im;
+
+ im = reg[IMSC];
+ disable(uart);
+ reg[IMSC] = im;
+}
+
+static void
+uarton(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ /* disable fifo */
+ reg[LCRH] &= ~FEN;
+ coherence();
+
+ /* enable uart */
+ reg[CR] = UARTEN | RXE | TXE;
+ coherence();
+}
+
+static void
+enable(Uart *uart, int ie)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ disable(uart);
+ if(ie){
+ intrenable(IRQuart, interrupt, uart, BUSUNKNOWN, uart->name);
+ reg[IMSC] = TXIM|RXIM;
+ }
+ uarton(uart);
+}
+
+static void
+linectl(Uart *uart, u32int set, u32int clr)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ if(uart->enabled)
+ uartoff(uart);
+
+ reg[LCRH] = set | (reg[LCRH] & ~clr);
+
+ if(uart->enabled)
+ uarton(uart);
+}
+
+static void
+kick(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ if(uart->blocked)
+ return;
+ coherence();
+ while((reg[FR] & TXFF) == 0){
+ if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
+ break;
+ reg[DR] = *(uart->op++);
+ }
+ coherence();
+}
+
+static void
+dobreak(Uart *uart, int ms)
+{
+ linectl(uart, BRK, 0);
+ delay(ms);
+ linectl(uart, 0, BRK);
+}
+
+static int
+baud(Uart *uart, int n)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ if(uart->freq <= 0 || n <= 0)
+ return -1;
+
+ if(uart->enabled)
+ uartoff(uart);
+
+ reg[IBRD] = (uart->freq >> 4) / n;
+ reg[FBRD] = (uart->freq >> 4) % n;
+
+ if(uart->enabled)
+ uarton(uart);
+
+ uart->baud = n;
+ return 0;
+}
+
+static int
+bits(Uart *uart, int n)
+{
+ switch(n){
+ case 8:
+ linectl(uart, WLEN8, WLENM);
+ break;
+ case 7:
+ linectl(uart, WLEN7, WLENM);
+ break;
+ case 6:
+ linectl(uart, WLEN6, WLENM);
+ break;
+ case 5:
+ linectl(uart, WLEN5, WLENM);
+ break;
+ default:
+ return -1;
+ }
+ uart->bits = n;
+ return 0;
+}
+
+static int
+stop(Uart *uart, int n)
+{
+ switch(n){
+ case 1:
+ linectl(uart, 0, STP2);
+ break;
+ case 2:
+ linectl(uart, STP2, 0);
+ break;
+ default:
+ return -1;
+ }
+ uart->stop = n;
+ return 0;
+}
+
+static int
+parity(Uart *uart, int n)
+{
+ switch(n){
+ case 'n':
+ linectl(uart, 0, PEN);
+ break;
+ case 'e':
+ linectl(uart, EPS|PEN, 0);
+ break;
+ case 'o':
+ linectl(uart, PEN, EPS);
+ break;
+ default:
+ return -1;
+ }
+ uart->parity = n;
+ return 0;
+}
+
+static void
+modemctl(Uart *uart, int on)
+{
+ uart->modem = on;
+}
+
+static void
+rts(Uart*, int)
+{
+}
+
+static long
+status(Uart *uart, void *buf, long n, long offset)
+{
+ char *p;
+
+ p = malloc(READSTR);
+ if(p == nil)
+ error(Enomem);
+ snprint(p, READSTR,
+ "b%d\n"
+ "dev(%d) type(%d) framing(%d) overruns(%d) "
+ "berr(%d) serr(%d)\n",
+
+ uart->baud,
+ uart->dev,
+ uart->type,
+ uart->ferr,
+ uart->oerr,
+ uart->berr,
+ uart->serr
+ );
+ n = readstr(offset, buf, n, p);
+ free(p);
+
+ return n;
+}
+
+static void
+donothing(Uart*, int)
+{
+}
+
+static void
+putc(Uart *uart, int c)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ while((reg[FR] & TXFF) != 0)
+ ;
+ reg[DR] = c & 0xFF;
+}
+
+static int
+getc(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ while((reg[FR] & RXFE) != 0)
+ ;
+ return reg[DR] & 0xFF;
+}
+
+void
+uartconsinit(void)
+{
+ consuart = &lx2kuart;
+ consuart->console = 1;
+ uartctl(consuart, "l8 pn s1");
+ uartputs(kmesg.buf, kmesg.n);
+}
+
+PhysUart lx2kphysuart = {
+ .name = "lx2k",
+ .pnp = pnp,
+ .enable = enable,
+ .disable = disable,
+ .kick = kick,
+ .dobreak = dobreak,
+ .baud = baud,
+ .bits = bits,
+ .stop = stop,
+ .parity = parity,
+ .modemctl = donothing,
+ .rts = rts,
+ .dtr = donothing,
+ .status = status,
+ .fifo = donothing,
+ .getc = getc,
+ .putc = putc,
+};
--- /dev/null
+++ b/sys/src/9/lx2k/usbxhcilx2k.c
@@ -1,0 +1,71 @@
+#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 "../port/usbxhci.h"
+
+static void
+coreinit(u32int *reg)
+{
+ enum {
+ GCTL = 0xC110/4,
+ PWRDNSCALE_SHIFT = 19,
+ PWRDNSCALE_MASK = 0x3FFF << PWRDNSCALE_SHIFT,
+ PRTCAPDIR_SHIFT = 12,
+ PRTCAPDIR_MASK = 3 << PRTCAPDIR_SHIFT,
+ DISSCRAMBLE = 1<<3,
+ DSBLCLKGTNG = 1<<0,
+
+ GUCTL = 0xC12C/4,
+ USBHSTINAUTORETRY = 1<<14,
+
+ GFLADJ = 0xC630/4,
+ GFLADJ_30MHZ_SDBND_SEL = 1<<7,
+ GFLADJ_30MHZ_SHIFT = 0,
+ GFLADJ_30MHZ_MASK = 0x3F << GFLADJ_30MHZ_SHIFT,
+
+ };
+ reg[GCTL] &= ~(PWRDNSCALE_MASK | DISSCRAMBLE | DSBLCLKGTNG | PRTCAPDIR_MASK);
+ reg[GCTL] |= 2<<PWRDNSCALE_SHIFT | 1<<PRTCAPDIR_SHIFT;
+ reg[GUCTL] |= USBHSTINAUTORETRY;
+ reg[GFLADJ] = (reg[GFLADJ] & ~GFLADJ_30MHZ_MASK) | 0x20<<GFLADJ_30MHZ_SHIFT | GFLADJ_30MHZ_SDBND_SEL;
+}
+
+static int
+reset(Hci *hp)
+{
+ static Xhci *ctlrs[2];
+ Xhci *ctlr;
+ int i;
+
+ for(i=0; i<nelem(ctlrs); i++){
+ if(ctlrs[i] == nil){
+ uintptr base = VIRTIO + 0x2100000 + i*0x10000;
+ ctlr = xhcialloc((u32int*)base, base - KZERO, 0x10000);
+ if(ctlr == nil)
+ break;
+ ctlrs[i] = ctlr;
+ goto Found;
+ }
+ }
+ return -1;
+
+Found:
+ hp->tbdf = BUSUNKNOWN;
+ hp->irq = IRQusb1 + i;
+ xhcilinkage(hp, ctlr);
+
+ coreinit(ctlr->mmio);
+
+ return 0;
+}
+
+void
+usbxhcilx2klink(void)
+{
+ addhcitype("xhci", reset);
+}
--- a/sys/src/boot/mkfile
+++ b/sys/src/boot/mkfile
@@ -2,6 +2,7 @@
bcm\
bitsy\
efi\
+ honeycomb\
pc\
qemu\
reform\
--
⑨