ref: fc968ae333c3e34f3b3b4cc36a3b856f0078ed16
parent: af517539e09f690d2fa3911a8d652fd45b39ce6e
author: moody <moody@sakuya>
date: Sat May 24 16:04:56 EDT 2025
riscv64: add non working WIP kernel Bootstrap MMU looks ok, uart causes fault
--- /dev/null
+++ b/sys/src/9/riscv64/clock.c
@@ -1,0 +1,56 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "sysreg.h"
+
+/* Fixed tick frequency in QEMU */
+static uvlong freq = 10000000;
+
+extern uvlong rdtime(void);
+
+void
+clockinit(void)
+{
+}
+
+void
+timerset(uvlong next)
+{
+ // TODO
+}
+
+uvlong
+fastticks(uvlong *hz)
+{
+ if(hz)
+ *hz = freq;
+ return rdtime();
+}
+
+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);
+}
--- /dev/null
+++ b/sys/src/9/riscv64/dat.h
@@ -1,0 +1,227 @@
+/*
+ * 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 */
+ FPnotify = 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 */
+ 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 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/riscv64/fns.h
@@ -1,0 +1,173 @@
+#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 hvccall(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 uintptr mmukmap(uintptr, uintptr, usize);
+extern void kmapram(uintptr, uintptr);
+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);
+
+/* 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);
+
+/* uartimx */
+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);
+
+/* pciqemu */
+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);
+
+/* bootargs */
+extern void bootargsinit(void);
--- /dev/null
+++ b/sys/src/9/riscv64/fpu.c
@@ -1,0 +1,24 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+#include "ureg.h"
+#include "../riscv64/sysreg.h"
+
+FPsave*
+notefpsave(Proc *p)
+{
+#ifdef XXX
+ if(p->fpsave == nil)
+ return nil;
+ if(p->fpstate == (FPinactive|FPnotify)){
+ p->fpsave = fpalloc(p->fpsave);
+ memmove(p->fpsave, p->fpsave->link, sizeof(FPsave));
+ p->fpstate = FPinactive;
+ }
+ return p->fpsave->link;
+#endif
+ return nil;
+}
--- /dev/null
+++ b/sys/src/9/riscv64/init9.s
@@ -1,0 +1,4 @@
+TEXT main(SB), 1, $8
+ MOV $setSB(SB), R3 /* load the SB */
+ MOV $boot(SB), R0
+ JAL R1, startboot(SB)
--- /dev/null
+++ b/sys/src/9/riscv64/io.h
@@ -1,0 +1,3 @@
+#define BUSUNKNOWN (-1)
+#define PCIWINDOW 0
+#define PCIWADDR(x) (PADDR(x)+PCIWINDOW)
--- /dev/null
+++ b/sys/src/9/riscv64/l.s
@@ -1,0 +1,167 @@
+#include <atom.h>
+#define ARG 8
+
+#include "mem.h"
+#include "sysreg.h"
+
+#define SFENCE WORD $0x12000073
+#define WFI WORD $0x10500073
+
+#define SATP_SV39 (8ULL<<60)
+#define MAKE_SATP(x) (SATP_SV39|((x)>>12))
+
+TEXT _start(SB), 1, $-4
+ MOV $setSB(SB), R3
+ JAL R1, mmudisable<>(SB)
+
+ MOV $(MACHADDR(0)-KZERO), R7
+ AND $(MAXMACH-1), R10
+ MOVW $MACHSIZE, R11
+ MULW R10, R11, R11
+ SUB R11, R7
+
+ ADD $(MACHSIZE-16), R7, R11
+ MOV R11, R2
+
+ MOV $(L1-KZERO), R11
+ MOV $(MACHADDR(-1)-KZERO), R12
+_zerol1:
+ MOV R0, (R11)
+ ADD $8, R11
+ BNE R11, R12, _zerol1
+
+ MOV $edata(SB), R11
+ MOV $end(SB), R12
+_zerobss:
+ MOV R0, (R11)
+ ADD $8, R11
+ BNE R11, R12, _zerobss
+
+ MOV $(L1-KZERO), R8
+ JAL R1, mmu0init(SB)
+
+ JAL R1, mmuenable<>(SB)
+
+ MOV $KTZERO, R11
+ MOV $zoinked<>(SB), R12
+ AND $(BY2PG-1), R12
+ ADD R11, R12, R12
+ JMP (R12)
+
+TEXT zoinked<>(SB), 1, $-4
+ MOV $setSB(SB), R3
+ JAL R1, main(SB)
+
+TEXT stop<>(SB), 1, $-4
+_stop:
+ WFI
+ JMP _stop
+
+TEXT mmudisable<>(SB), 1, $-4
+ SFENCE
+ MOV R0, CSR(SATP)
+ SFENCE
+ RET
+
+TEXT mmuenable<>(SB), 1, $-4
+ MOV $MAKE_SATP(L1-KZERO), R8
+ SFENCE
+ MOV R8, CSR(SATP)
+ SFENCE
+ RET
+
+TEXT cas(SB), 1, $-4
+TEXT cmpswap(SB), 1, $-4
+ MOVWU ov+8(FP), R12
+ MOVWU nv+(8+4)(FP), R13
+ MOV R0, R11
+ FENCE_RW
+_spincas:
+ LRW(ARG, 14)
+ SLL $32, R14
+ SRL $32, R14
+ BNE R12, R14, _fail
+ FENCE_RW
+ SCW(13, ARG, 14)
+ BNE R14, _spincas
+ MOV $1, R11
+_fail:
+ FENCE_RW
+ MOV R11, R(ARG)
+ RET
+
+TEXT tas(SB), 1, $-4
+TEXT _tas(SB), 1, $-4
+ MOV $1, R10
+ FENCE_RW
+ AMOW(Amoswap, AQ|RL, 10, ARG, ARG)
+ FENCE_RW
+ RET
+
+TEXT setlabel(SB), 1, $-4
+ MOV R2, (R8)
+ MOV R1, 8(R8)
+ MOV R0, R8
+ RET
+
+TEXT gotolabel(SB), 1, $-4
+ MOVW r+8(FP), R13
+ BNE R13, _ok
+ MOV $1, R13
+_ok: MOV (R8), R2
+ MOV 8(R8), R1
+ MOV R13, R8
+ RET
+
+TEXT rdtime(SB), 1, $-4
+ FENCE
+ MOV CSR(TIME), R8
+ RET
+
+TEXT coherence(SB), 1, $-4
+ FENCE
+ RET
+
+TEXT islo(SB), 1, $-4
+ RET
+
+TEXT splhi(SB), 1, $-4
+ RET
+
+TEXT spllo(SB), 1, $-4
+ RET
+
+TEXT splx(SB), 1, $-4
+ RET
+
+TEXT flushtlb(SB), 1, $-4
+ RET
+TEXT flushasidvall(SB), 1, $-4
+ RET
+TEXT flushasidva(SB), 1, $-4
+ RET
+TEXT flushasid(SB), 1, $-4
+ RET
+
+TEXT cachedwbinvse(SB), 1, $-4
+ RET
+TEXT cacheiinvse(SB), 1, $-4
+ RET
+
+TEXT vcycles(SB), 1, $-4
+ RET
+TEXT perfticks(SB), 1, $-4
+ RET
+
+ /* rename as we don't have ttbr */
+TEXT setttbr(SB), 1, $-4
+ RET
+
+
+TEXT idlehands(SB), 1, $-4
+ FENCE
+ MOVW nrdy(SB), R8
+ BNE R8, R0, _ready
+ WFI
+_ready:
+ RET
--- /dev/null
+++ b/sys/src/9/riscv64/main.c
@@ -1,0 +1,323 @@
+#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 "sysreg.h"
+#include "ureg.h"
+
+//#include "rebootcode.i"
+
+Conf conf;
+
+int
+isaconfig(char *, int, ISAConf *)
+{
+ return 0;
+}
+
+/*
+ * starting place for first process
+ */
+void
+init0(void)
+{
+#ifdef XXX
+ 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);
+#endif
+}
+
+void
+confinit(void)
+{
+ int userpcnt;
+ ulong kpages;
+ char *p;
+ int i;
+
+ conf.nmach = 1;
+ if(p = getconf("*ncpu"))
+ conf.nmach = strtol(p, 0, 0);
+ if(conf.nmach > MAXMACH)
+ 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;
+}
+
+void
+mpinit(void)
+{
+#ifdef XXX
+ extern void _start(void);
+ int i;
+
+ for(i = 1; i < conf.nmach; i++){
+ Ureg u = {0};
+
+ MACHP(i)->machno = i;
+ cachedwbinvse(MACHP(i), MACHSIZE);
+
+ u.r0 = 0x84000003; /* CPU_ON */
+ u.r1 = (sysrd(MPIDR_EL1) & ~(0xFF0000FFULL)) | i;
+ u.r2 = PADDR(_start);
+ u.r3 = i;
+ hvccall(&u);
+ }
+ synccycles();
+#endif
+}
+
+void
+cpuidprint(void)
+{
+ iprint("cpu%d: 1000MHz QEMU\n", m->machno);
+}
+
+char *
+getconf(char *name)
+{
+ return nil;
+}
+
+void
+main(void)
+{
+ machinit();
+#ifdef XXX
+ if(m->machno){
+ trapinit();
+ fpuinit();
+ intrinit();
+ clockinit();
+ cpuidprint();
+ synccycles();
+ timersinit();
+ mmu1init();
+ m->ticks = MACHP(0)->ticks;
+ schedinit();
+ return;
+ }
+#endif
+ uartconsinit();
+#ifdef XXX
+ quotefmtinstall();
+ bootargsinit();
+ meminit();
+ confinit();
+ xinit();
+ printinit();
+ print("\nPlan 9\n");
+#endif
+ for(;;);
+#ifdef XXX
+ trapinit();
+ fpuinit();
+ intrinit();
+ clockinit();
+ cpuidprint();
+ timersinit();
+ pageinit();
+ procinit0();
+ initseg();
+ links();
+ chandevreset();
+ userinit();
+ mpinit();
+ mmu1init();
+ schedinit();
+#endif
+}
+
+void
+exit(int)
+{
+#ifdef XXX
+ Ureg u = { .r0 = 0x84000002 }; /* CPU_OFF */
+
+ cpushutdown();
+ splfhi();
+
+ if(m->machno == 0){
+ /* clear secrets */
+ zeroprivatepages();
+ poolreset(secrmem);
+
+ u.r0 = 0x84000009; /* SYSTEM RESET */
+ }
+ hvccall(&u);
+#endif
+}
+
+static void
+rebootjump(void *entry, void *code, ulong size)
+{
+#ifdef XXX
+ 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);
+#endif
+
+ for(;;);
+}
+
+void
+reboot(void*, void *code, ulong size)
+{
+#ifdef XXX
+ 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);
+#endif
+}
+
+void
+dmaflush(int clean, void *p, ulong len)
+{
+#ifdef XXX
+ 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);
+#endif
+}
--- /dev/null
+++ b/sys/src/9/riscv64/mem.c
@@ -1,0 +1,61 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+#define INITMAP (ROUND((uintptr)end + BY2PG, PGLSZ(1)))
+
+void
+mmu0init(uintptr *l1)
+{
+ uintptr va, pa, pe, attr;
+
+ /* VDRAM */
+ attr = PTEREAD | PTEWRITE | PTEEXEC;
+ pe = -KZERO;
+ for(pa = VDRAM - KZERO; pa < pe; pa += PGLSZ(PTLEVELS-1))
+ l1[PTLX(pa, PTLEVELS-1)] = PA2PTE(pa) | PTEVALID | attr;
+
+ /* DRAM - INITMAP */
+ pe = INITMAP;
+ for(pa = VDRAM - KZERO, va = VDRAM; pa < pe; pa += PGLSZ(1), va += PGLSZ(1))
+ l1[PTL1X(va, 1)] = PA2PTE(pa) | PTEVALID | attr;
+
+ /* VIRTIO */
+ attr = PTEREAD | PTEWRITE | 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)] = PA2PTE((uintptr)l1) | PTEVALID;
+ 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)] = PA2PTE(pa) | PTEVALID | attr;
+ }
+ break;
+ }
+ l1[PTL1X(va, 1)] = PA2PTE(pa) | PTEVALID | attr;
+ }
+
+ if(PTLEVELS > 2)
+ for(va = KSEG0; va != 0; va += PGLSZ(2))
+ l1[PTLX(va, 2)] = PA2PTE((uintptr)&l1[L1TABLEX(va, 1)]) | PTEVALID;
+}
+
+void
+meminit(void)
+{
+ char *p;
+ uintptr l = GiB + 128 * MiB;
+
+ if(p = getconf("*maxmem"))
+ l = strtoull(p, 0, 0);
+ conf.mem[0].base = PGROUND((uintptr)end);
+ conf.mem[0].limit = l;
+
+ if(l > KLIMIT)
+ l = KLIMIT;
+ kmapram(conf.mem[0].base, l);
+
+ conf.mem[0].npage = (conf.mem[0].limit - conf.mem[0].base)/BY2PG;
+}
--- /dev/null
+++ b/sys/src/9/riscv64/mem.h
@@ -1,0 +1,118 @@
+/*
+ * 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 39
+#define EVAMASK ((1ULL<<EVASHIFT)-1)
+
+#define PTSHIFT (PGSHIFT-3)
+#define PTLEVELS (((EVASHIFT-PGSHIFT)+PTSHIFT-1)/PTSHIFT)
+/* PPN */
+#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 MAXMACH 8 /* 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 - */
+#define KTZERO (VDRAM + 0x200000) /* 0x80200000 - kernel text start */
+
+#define PHYSIO 0
+#define PHYSIOEND 0x20000000
+
+#define VIRTIO (0xFFFFFFFFA0000000ULL)
+
+#define KZERO (0xFFFFFFFF40000000ULL) /* 0x00000000 - kernel address space */
+
+#define VMAP (0xFFFFFFFF00000000ULL) /* 0x00000000 - 0x40000000 */
+
+#define KMAPEND (0xFFFFFFFF00000000ULL) /* 0x140000000 */
+#define KMAP (0xFFFFFFFE00000000ULL) /* 0x40000000 */
+
+#define KLIMIT (VDRAM - KZERO + KMAPEND - KMAP) /* 0x140000000 */
+
+#define KSEG0 (0xFFFFFFFE00000000ULL)
+
+/* 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 PTEVALID (1<<0)
+#define PTEREAD (1<<1)
+#define PTEWRITE (1<<2)
+#define PTEEXEC (1<<3)
+#define PTEUSER (1<<4)
+#define PTECACHED 0
+#define PTEUNCACHED 0
+#define PTEDEVICE 0 /* FIXME */
+#define PTERONLY PTEREAD
+
+#define PA2PTE(pa) ((pa>>12)<<10)
+#define PTE2PA(pte) ((pte>>10)<<12)
+
+/*
+ * 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/riscv64/mkfile
@@ -1,0 +1,99 @@
+CONF=qemu
+CONFLIST=qemu
+
+loadaddr=0xffffffffc0200000
+
+objtype=riscv64
+</$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\
+ random.$O\
+ rdb.$O\
+ rebootcmd.$O\
+ segment.$O\
+ syscallfmt.$O\
+ sysfile.$O\
+ sysproc.$O\
+ taslock.$O\
+ tod.$O\
+ xalloc.$O\
+ userinit.$O\
+
+OBJ=\
+ l.$O\
+ main.$O\
+ mmu.$O\
+ mem.$O\
+ trap.$O\
+ clock.$O\
+ fpu.$O\
+ $CONF.root.$O\
+ $CONF.rootc.$O\
+ $DEVS\
+ $PORT\
+
+# HFILES=
+
+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 s$p$CONF
+
+$p$CONF:D: $OBJ $CONF.$O $LIB
+ $LD -s -l -o $target -H6 -R0x1000 -T$loadaddr $prereq
+
+s$p$CONF:D: $OBJ $CONF.$O $LIB
+ $LD -l -o $target -R0x1000 -T$loadaddr $prereq
+ size $target
+
+$OBJ: $HFILES
+
+install:V: /$objtype/$p$CONF
+
+/$objtype/$p$CONF:D: $p$CONF s$p$CONF
+ cp -x $p$CONF s$p$CONF /$objtype/
+
+<../boot/bootmkfile
+<../port/portmkfile
+<|../port/mkbootrules $CONF
+
+#main.$O: rebootcode.i
+
+pciqemu.$O: ../port/pci.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 -T0x40020000 -s -o $target $prereq
+
+$CONF.clean:
+ rm -rf $p$CONF s$p$CONF errstr.h $CONF.c boot$CONF.c
--- /dev/null
+++ b/sys/src/9/riscv64/mmu.c
@@ -1,0 +1,372 @@
+#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)
+
+void
+mmu1init(void)
+{
+ m->mmutop = mallocalign(L1TOPSIZE, BY2PG, 0, 0);
+ if(m->mmutop == nil)
+ panic("mmu1init: no memory for mmutop");
+ memset(m->mmutop, 0, L1TOPSIZE);
+ mmuswitch(nil);
+}
+
+/* KZERO maps the first 1GB of ram */
+uintptr
+paddr(void *va)
+{
+ if((uintptr)va >= KZERO)
+ return (uintptr)va-KZERO;
+ panic("paddr: va=%#p pc=%#p", va, getcallerpc(&va));
+}
+
+uintptr
+cankaddr(uintptr pa)
+{
+ if(pa < (uintptr)-KZERO)
+ return -KZERO - pa;
+ return 0;
+}
+
+void*
+kaddr(uintptr pa)
+{
+ if(pa < (uintptr)-KZERO)
+ return (void*)(pa + KZERO);
+ panic("kaddr: pa=%#p pc=%#p", pa, getcallerpc(&pa));
+}
+
+static void*
+kmapaddr(uintptr pa)
+{
+ if(pa < (uintptr)-KZERO)
+ return (void*)(pa + KZERO);
+ if(pa < (VDRAM - KZERO) || pa >= (VDRAM - KZERO) + (KMAPEND - KMAP))
+ panic("kmapaddr: pa=%#p pc=%#p", pa, getcallerpc(&pa));
+ return (void*)(pa + KMAP - (VDRAM - KZERO));
+}
+
+KMap*
+kmap(Page *p)
+{
+ return kmapaddr(p->pa);
+}
+
+void
+kunmap(KMap*)
+{
+}
+
+void
+kmapinval(void)
+{
+}
+
+static void*
+rampage(void)
+{
+ uintptr pa;
+
+ if(conf.npage)
+ return mallocalign(BY2PG, BY2PG, 0, 0);
+
+ pa = conf.mem[0].base;
+ assert((pa % BY2PG) == 0);
+ conf.mem[0].base += BY2PG;
+ return KADDR(pa);
+}
+
+static void
+l1map(uintptr va, uintptr pa, uintptr pe, uintptr attr)
+{
+ uintptr *l1, *l0;
+
+ assert(pa < pe);
+
+ va &= -BY2PG;
+ pa &= -BY2PG;
+ pe = PGROUND(pe);
+
+ l1 = (uintptr*)L1;
+
+ while(pa < pe){
+ if(l1[PTL1X(va, 1)] == 0 && (pe-pa) >= PGLSZ(1) && ((va|pa) & PGLSZ(1)-1) == 0){
+ l1[PTL1X(va, 1)] = PTEVALID | PA2PTE(pa) | attr;
+ va += PGLSZ(1);
+ pa += PGLSZ(1);
+ continue;
+ }
+ if(l1[PTL1X(va, 1)] & PTEVALID) {
+// assert((l1[PTL1X(va, 1)] & PTETABLE) == PTETABLE);
+ l0 = KADDR(l1[PTL1X(va, 1)] & -PGLSZ(0));
+ } else {
+ l0 = rampage();
+ memset(l0, 0, BY2PG);
+ l1[PTL1X(va, 1)] = PTEVALID | PA2PTE(PADDR(l0));
+ }
+ assert(l0[PTLX(va, 0)] == 0);
+ l0[PTLX(va, 0)] = PTEVALID | PA2PTE(pa) | attr;
+ va += BY2PG;
+ pa += BY2PG;
+ }
+}
+
+void
+kmapram(uintptr base, uintptr limit)
+{
+ if(base < (uintptr)-KZERO && limit > (uintptr)-KZERO){
+ kmapram(base, (uintptr)-KZERO);
+ kmapram((uintptr)-KZERO, limit);
+ return;
+ }
+ if(base < INITMAP)
+ base = INITMAP;
+ if(base >= limit || limit <= INITMAP)
+ return;
+
+ l1map((uintptr)kmapaddr(base), base, limit,
+ PTEWRITE | PTEREAD);
+}
+
+uintptr
+mmukmap(uintptr va, uintptr pa, usize size)
+{
+ uintptr attr, off;
+
+ if(va == 0)
+ return 0;
+
+ off = pa & BY2PG-1;
+
+// TODO: When we support memory access cache flags, need to do a copy here
+// attr = va & PTEMA(7);
+ attr |= PTEWRITE | PTEREAD;
+
+ va &= -BY2PG;
+ pa &= -BY2PG;
+
+ l1map(va, pa, pa + off + size, attr);
+ flushtlb();
+
+ return va + off;
+}
+
+void*
+vmap(uvlong pa, vlong size)
+{
+ static uintptr base = VMAP;
+ uvlong pe = pa + size;
+ uintptr va;
+
+ va = base;
+ base += PGROUND(pe) - (pa & -BY2PG);
+
+ return (void*)mmukmap(va | PTEDEVICE, pa, size);
+}
+
+void
+vunmap(void *, vlong)
+{
+}
+
+static uintptr*
+mmuwalk(uintptr va, int level)
+{
+ uintptr *table, pte;
+ Page *pg;
+ int i, x;
+
+ x = PTLX(va, PTLEVELS-1);
+ table = m->mmutop;
+ for(i = PTLEVELS-2; i >= level; i--){
+ pte = table[x];
+ if(pte & PTEVALID) {
+ if(pte & (0xFFFFULL<<48))
+ iprint("strange pte %#p va %#p\n", pte, va);
+ pte &= ~(0xFFFFULL<<48 | BY2PG-1);
+ } else {
+ pg = up->mmufree;
+ if(pg == nil)
+ return nil;
+ up->mmufree = pg->next;
+ pg->va = va & -PGLSZ(i+1);
+ if((pg->next = up->mmuhead[i+1]) == nil)
+ up->mmutail[i+1] = pg;
+ up->mmuhead[i+1] = pg;
+ pte = pg->pa;
+ memset(kmapaddr(pte), 0, BY2PG);
+ coherence();
+ table[x] = pte | PTEVALID; // XXX: Does this need PA2PTE
+ }
+ table = kmapaddr(pte);
+ x = PTLX(va, (uintptr)i);
+ }
+ return &table[x];
+}
+
+static Proc *asidlist[256];
+
+static int
+allocasid(Proc *p)
+{
+ static Lock lk;
+ Proc *x;
+ int a;
+
+ lock(&lk);
+ a = p->asid;
+ if(a < 0)
+ a = -a;
+ if(a == 0)
+ a = p->pid;
+ for(;; a++){
+ a %= nelem(asidlist);
+ if(a == 0)
+ continue; // reserved
+ x = asidlist[a];
+ if(x == p || x == nil || (x->asid < 0 && x->mach == nil))
+ break;
+ }
+ p->asid = a;
+ asidlist[a] = p;
+ unlock(&lk);
+
+ return x != p;
+}
+
+static void
+freeasid(Proc *p)
+{
+ int a;
+
+ a = p->asid;
+ if(a < 0)
+ a = -a;
+ if(a > 0 && asidlist[a] == p)
+ asidlist[a] = nil;
+ p->asid = 0;
+}
+
+void
+putasid(Proc *p)
+{
+ /*
+ * Prevent the following scenario:
+ * pX sleeps on cpuA, leaving its page tables in mmutop
+ * pX wakes up on cpuB, and exits, freeing its page tables
+ * pY on cpuB allocates a freed page table page and overwrites with data
+ * cpuA takes an interrupt, and is now running with bad page tables
+ * In theory this shouldn't hurt because only user address space tables
+ * are affected, and mmuswitch will clear mmutop before a user process is
+ * dispatched. But empirically it correlates with weird problems, eg
+ * resetting of the core clock at 0x4000001C which confuses local timers.
+ */
+ if(conf.nmach > 1)
+ mmuswitch(nil);
+
+ if(p->asid > 0)
+ p->asid = -p->asid;
+}
+
+void
+putmmu(uintptr va, uintptr pa, Page *pg)
+{
+ uintptr *pte, old;
+ int s;
+
+ s = splhi();
+ while((pte = mmuwalk(va, 0)) == nil){
+ spllo();
+ up->mmufree = newpage(0, nil, 0);
+ splhi();
+ }
+ old = *pte;
+ *pte = 0;
+ if((old & PTEVALID) != 0)
+ flushasidvall((uvlong)up->asid<<48 | va>>12);
+ else
+ flushasidva((uvlong)up->asid<<48 | va>>12);
+ *pte = PA2PTE(pa) | PTEVALID | PTEUSER;
+ if(needtxtflush(pg)){
+ cachedwbinvse(kmap(pg), BY2PG);
+ cacheiinvse((void*)va, BY2PG);
+ donetxtflush(pg);
+ }
+ splx(s);
+}
+
+static void
+mmufree(Proc *p)
+{
+ int i;
+
+ freeasid(p);
+
+ for(i=1; i<PTLEVELS; i++){
+ if(p->mmuhead[i] == nil)
+ break;
+ p->mmutail[i]->next = p->mmufree;
+ p->mmufree = p->mmuhead[i];
+ p->mmuhead[i] = p->mmutail[i] = nil;
+ }
+}
+
+void
+mmuswitch(Proc *p)
+{
+ uintptr va;
+ Page *t;
+
+ for(va = UZERO; va < USTKTOP; va += PGLSZ(PTLEVELS-1))
+ m->mmutop[PTLX(va, PTLEVELS-1)] = 0;
+
+ if(p == nil){
+ setttbr(PADDR(m->mmutop));
+ return;
+ }
+
+ if(p->newtlb){
+ mmufree(p);
+ p->newtlb = 0;
+ }
+
+ if(allocasid(p))
+ flushasid((uvlong)p->asid<<48);
+
+ setttbr((uvlong)p->asid<<48 | PADDR(m->mmutop));
+
+ for(t = p->mmuhead[PTLEVELS-1]; t != nil; t = t->next){
+ va = t->va;
+ m->mmutop[PTLX(va, PTLEVELS-1)] = t->pa | PTEVALID;
+ }
+}
+
+void
+mmurelease(Proc *p)
+{
+ mmuswitch(nil);
+ mmufree(p);
+ freepages(p->mmufree, nil, 0);
+ p->mmufree = nil;
+}
+
+void
+flushmmu(void)
+{
+ int x;
+
+ x = splhi();
+ up->newtlb = 1;
+ mmuswitch(up);
+ splx(x);
+}
+
+void
+checkmmu(uintptr, uintptr)
+{
+}
--- /dev/null
+++ b/sys/src/9/riscv64/qemu
@@ -1,0 +1,52 @@
+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
+# rtc
+# pci pci
+ sd
+
+#link
+# usbxhcipci pci usbxhci
+# ethervirtio10 pci
+# ethersink
+# ethermedium
+# loopbackmedium
+# netdevmedium
+# pciqemu pci
+
+#ip
+# tcp
+# udp
+# il
+# ipifc
+# icmp
+# icmp6
+# igmp
+# ipmux
+misc
+# gic
+ uartqemu
+# sdvirtio10 pci sdscsi
+port
+ int cpuserver = 0;
+bootdir
+ /$objtype/bin/paqfs
+ /$objtype/bin/auth/factotum
+ bootfs.paq
+ boot
--- /dev/null
+++ b/sys/src/9/riscv64/sysreg.h
@@ -1,0 +1,2 @@
+#define SATP 0x180
+#define TIME 0xc01
--- /dev/null
+++ b/sys/src/9/riscv64/trap.c
@@ -1,0 +1,161 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+#include "../port/systab.h"
+
+#include <tos.h>
+#include "ureg.h"
+#include "../riscv64/sysreg.h"
+
+void
+setupwatchpts(Proc*, Watchpt*, int)
+{
+}
+
+void
+dumpstack(void)
+{
+ // TODO
+}
+
+void
+setregisters(Ureg* ureg, char* pureg, char* uva, int n)
+{
+ ulong v;
+
+ v = ureg->ie;
+ memmove(pureg, uva, n);
+ ureg->ie = v;
+}
+
+uintptr
+userpc(void)
+{
+ Ureg *ur = up->dbgreg;
+ return ur->pc;
+}
+
+uintptr
+dbgpc(Proc *)
+{
+ Ureg *ur = up->dbgreg;
+ if(ur == nil)
+ return 0;
+ return ur->pc;
+}
+
+void
+procfork(Proc *p)
+{
+// fpuprocfork(p);
+// p->tpidr = up->tpidr;
+}
+
+void
+procsetup(Proc *p)
+{
+// fpuprocsetup(p);
+// p->tpidr = 0;
+// syswr(TPIDR_EL0, p->tpidr);
+}
+
+void
+procsave(Proc *p)
+{
+// fpuprocsave(p);
+// if(p->kp == 0)
+// p->tpidr = sysrd(TPIDR_EL0);
+// putasid(p); // release asid
+}
+
+void
+procrestore(Proc *p)
+{
+// fpuprocrestore(p);
+// if(p->kp == 0)
+// syswr(TPIDR_EL0, p->tpidr);
+}
+
+void
+setkernur(Ureg *ureg, Proc *p)
+{
+ ureg->pc = p->sched.pc;
+ ureg->sp = p->sched.sp;
+ ureg->link = (uintptr)sched;
+}
+
+int
+userureg(Ureg* ureg)
+{
+ return 0;
+}
+
+void
+callwithureg(void (*f) (Ureg *))
+{
+#ifdef XXX
+ Ureg u;
+
+ u.pc = getcallerpc(&f);
+ u.sp = (uintptr) &f;
+ f(&u);
+#endif
+}
+
+void
+kprocchild(Proc *p, void (*entry)(void))
+{
+#ifdef XXX
+ p->sched.pc = (uintptr) entry;
+ p->sched.sp = (uintptr) p - 16;
+ *(void**)p->sched.sp = kprocchild; /* fake */
+#endif
+}
+
+void
+evenaddr(uintptr addr)
+{
+#ifdef XXX
+ if(addr & 3){
+ postnote(up, 1, "sys: odd address", NDebug);
+ error(Ebadarg);
+ }
+#endif
+}
+
+void
+forkchild(Proc *p, Ureg *ureg)
+{
+#ifdef XXX
+ Ureg *cureg;
+
+ p->sched.pc = (uintptr) forkret;
+ p->sched.sp = (uintptr) p - TRAPFRAMESIZE;
+
+ cureg = (Ureg*) (p->sched.sp + 16);
+ memmove(cureg, ureg, sizeof(Ureg));
+ cureg->r0 = 0;
+#endif
+}
+
+uintptr
+execregs(uintptr entry, ulong ssize, ulong nargs)
+{
+#ifdef XXX
+ uintptr *sp;
+ Ureg *ureg;
+
+ sp = (uintptr*)(USTKTOP - ssize);
+ *--sp = nargs;
+
+ ureg = up->dbgreg;
+ ureg->sp = (uintptr)sp;
+ ureg->pc = entry;
+ ureg->link = 0;
+ return USTKTOP-sizeof(Tos);
+#endif
+ return 0;
+}
--- /dev/null
+++ b/sys/src/9/riscv64/uartqemu.c
@@ -1,0 +1,336 @@
+/*
+ * 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 qemuphysuart;
+
+static Uart qemuuart = {
+ .regs = (u32int*)(VIRTIO+0x10000000ULL),
+ .name = "uart0",
+ .freq = 24*Mhz,
+ .baud = 115200,
+ .phys = &qemuphysuart,
+};
+
+static Uart*
+pnp(void)
+{
+ return &qemuuart;
+}
+
+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;
+
+ /* enable 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;
+
+ 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 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 = &qemuuart;
+ consuart->console = 1;
+ uartctl(consuart, "l8 pn s1");
+ for(;;) putc(consuart, 'A');
+}
+
+PhysUart qemuphysuart = {
+ .name = "qemu",
+ .pnp = pnp,
+ .enable = enable,
+ .disable = disable,
+ .kick = kick,
+ .dobreak = dobreak,
+ .baud = baud,
+ .bits = bits,
+ .stop = stop,
+ .parity = parity,
+ .modemctl = donothing,
+ .rts = rts,
+ .dtr = donothing,
+ .fifo = donothing,
+ .getc = getc,
+ .putc = putc,
+};
--
⑨