refactor arch split to handle multiple cpus Reference: /n/atom/patch/applied/piarchrefactor Date: Sun Jan 3 07:53:33 CET 2016 Signed-off-by: quanstro@quanstro.net --- /sys/src/9/bcm/dat.h Sun Jan 3 07:53:04 2016 +++ /sys/src/9/bcm/dat.h Sun Jan 3 07:53:05 2016 @@ -295,5 +295,8 @@ uintptr physio; uintptr busdram; uintptr busio; + uintptr armlocal; + u32int l1ptedramattrs; + u32int l2ptedramattrs; }; extern Soc soc; --- /sys/src/9/bcm/archbcm.c Sun Jan 3 07:53:07 2016 +++ /sys/src/9/bcm/archbcm.c Sun Jan 3 07:53:08 2016 @@ -95,6 +95,18 @@ print("cpu%d: %dMHz ARM %s\n", m->machno, m->cpumhz, name); } +int +getncpus(void) +{ + return 1; +} + +int +startcpus(uint) +{ + return 1; +} + void archbcmlink(void) { @@ -121,3 +133,72 @@ { return (AP(3, (ap))|AP(2, (ap))|AP(1, (ap))|AP(0, (ap))); } + +/* + * atomic ops + * make sure that we don't drag in the C library versions + */ + +long +_xdec(long *p) +{ + int s, v; + + s = splhi(); + v = --*p; + splx(s); + return v; +} + +void +_xinc(long *p) +{ + int s; + + s = splhi(); + ++*p; + splx(s); +} + +int +ainc(int *p) +{ + int s, v; + + s = splhi(); + v = ++*p; + splx(s); + return v; +} + +int +adec(int *p) +{ + int s, v; + + s = splhi(); + v = --*p; + splx(s); + return v; +} + +int +cas32(void* addr, u32int old, u32int new) +{ + int r, s; + + s = splhi(); + if(r = (*(u32int*)addr == old)) + *(u32int*)addr = new; + splx(s); + if (r) + coherence(); + return r; +} + +int +cmpswap(long *addr, long old, long new) +{ + return cas32(addr, old, new); +} + --- /sys/src/9/bcm/archbcm2.c Sun Jan 3 07:53:10 2016 +++ /sys/src/9/bcm/archbcm2.c Sun Jan 3 07:53:11 2016 @@ -14,13 +14,20 @@ #include "../port/netif.h" #include "etherif.h" +typedef struct Mbox Mbox; +typedef struct Mboxes Mboxes; + #define POWERREGS (VIRTIO+0x100000) +#define ARMLOCAL (VIRTIO+IOSIZE) Soc soc = { .dramsize = 1024*MiB, .physio = 0x3F000000, .busdram = 0xC0000000, .busio = 0x7E000000, + .armlocal = 0x40000000, + .l1ptedramattrs = Cached | Buffered | L1wralloc | L1sharable, + .l2ptedramattrs = Cached | Buffered | L2wralloc | L2sharable, }; enum { @@ -40,6 +47,26 @@ Wdog = 0x24>>2, }; +/* + * Arm local regs for smp + */ +struct Mbox { + u32int doorbell; + u32int mbox1; + u32int mbox2; + u32int startcpu; +}; +struct Mboxes { + Mbox set[4]; + Mbox clr[4]; +}; + +enum { + Mboxregs = 0x80 +}; + +static Lock startlock[MAXMACH + 1]; + void archreset(void) { @@ -77,7 +104,7 @@ r = (u32int*)POWERREGS; r[Rstc] = Password | (r[Rstc] & ~CfgMask); } - + char * cputype2name(char *buf, int size) { @@ -100,6 +127,57 @@ print("cpu%d: %dMHz ARM %s\n", m->machno, m->cpumhz, name); } +int +getncpus(void) +{ + int n, max; + char *p; + + n = 4; + if(n > MAXMACH) + n = MAXMACH; + p = getconf("*ncpu"); + if(p && (max = atoi(p)) > 0 && n > max) + n = max; + return n; +} + +static int +startcpu(uint cpu) +{ + Mboxes *mb; + int i; + void cpureset(); + + mb = (Mboxes*)(ARMLOCAL + Mboxregs); + if(mb->clr[cpu].startcpu) + return -1; + mb->set[cpu].startcpu = PADDR(cpureset); + for(i = 0; i < 1000; i++) + if(mb->clr[cpu].startcpu == 0) + return 0; + mb->clr[cpu].startcpu = PADDR(cpureset); + mb->set[cpu].doorbell = 1; + return 0; +} + +int +startcpus(uint ncpu) +{ + int i; + + for(i = 0; i < ncpu; i++) + lock(&startlock[i]); + cachedwbse(startlock, sizeof startlock); + for(i = 1; i < ncpu; i++){ + if(startcpu(i) < 0) + return i; + lock(&startlock[i]); + unlock(&startlock[i]); + } + return ncpu; +} + void archbcm2link(void) { @@ -125,4 +203,32 @@ l2ap(int ap) { return (AP(0, (ap))); +} + +int +cmpswap(long *addr, long old, long new) +{ + return cas((ulong*)addr, old, new); +} + +void +cpustart(int cpu) +{ + Mboxes *mb; + void machon(int); + + up = nil; + machinit(); + mmuinit1(m->mmul1); + mb = (Mboxes*)(ARMLOCAL + Mboxregs); + mb->clr[cpu].doorbell = 1; + trapinit(); + clockinit(); + timersinit(); + cpuidprint(); + archreset(); + machon(m->machno); + unlock(&startlock[cpu]); + schedinit(); + panic("schedinit returned"); } --- /sys/src/9/bcm/arch.c Sun Jan 3 07:53:13 2016 +++ /sys/src/9/bcm/arch.c Sun Jan 3 07:53:14 2016 @@ -1 +1,161 @@ -#include "../omap/arch.c" +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include +#include "ureg.h" + +#include "arm.h" + +/* + * A lot of this stuff doesn't belong here + * but this is a convenient dumping ground for + * later sorting into the appropriate buckets. + */ + +/* Give enough context in the ureg to produce a kernel stack for + * a sleeping process + */ +void +setkernur(Ureg* ureg, Proc* p) +{ + ureg->pc = p->sched.pc; + ureg->sp = p->sched.sp+4; + ureg->r14 = PTR2UINT(sched); +} + +/* + * called in syscallfmt.c, sysfile.c, sysproc.c + */ +void +validalign(uintptr addr, uint) +{ + if(addr & 3){ + postnote(up, 1, "sys: odd address", NDebug); + error(Ebadarg); + } +} + +/* go to user space */ +void +kexit(Ureg*) +{ + uvlong t; + Tos *tos; + + /* precise time accounting, kernel exit */ + tos = (Tos*)(USTKTOP-sizeof(Tos)); + cycles(&t); + tos->kcycles += t - up->kentry; + tos->pcycles = up->pcycles; + tos->cyclefreq = m->cpuhz; + tos->pid = up->pid; + + /* make visible immediately to user proc */ + cachedwbinvse(tos, sizeof *tos); +} + +/* + * return the userpc the last exception happened at + */ +uintptr +userpc(void) +{ + Ureg *ureg = up->dbgreg; + return ureg->pc; +} + +/* This routine must save the values of registers the user is not permitted + * to write from devproc and then restore the saved values before returning. + */ +void +setregisters(Ureg* ureg, char* pureg, char* uva, int n) +{ + USED(ureg, pureg, uva, n); +} + +/* + * this is the body for all kproc's + */ +static void +linkproc(void) +{ + spllo(); + up->kpfun(up->kparg); + pexit("kproc exiting", 0); +} + +/* + * setup stack and initial PC for a new kernel proc. This is architecture + * dependent because of the starting stack location + */ +void +kprocchild(Proc *p, void (*func)(void*), void *arg) +{ + p->sched.pc = PTR2UINT(linkproc); + p->sched.sp = PTR2UINT(p->kstack+KSTACK); + + p->kpfun = func; + p->kparg = arg; +} + +/* + * pc output by dumpaproc + */ +uintptr +dbgpc(Proc* p) +{ + Ureg *ureg; + + ureg = p->dbgreg; + if(ureg == 0) + return 0; + + return ureg->pc; +} + +/* + * set mach dependent process state for a new process + */ +void +procsetup(Proc* p) +{ + fpusysprocsetup(p); +} + +/* + * Save the mach dependent part of the process state. + */ +void +procsave(Proc* p) +{ + uvlong t; + + cycles(&t); + p->pcycles += t; + +// TODO: save and restore VFPv3 FP state once 5[cal] know the new registers. + fpuprocsave(p); +} + +void +procrestore(Proc* p) +{ + uvlong t; + + if(p->kp) + return; + cycles(&t); + p->pcycles -= t; + + fpuprocrestore(p); +} + +int +userureg(Ureg* ureg) +{ + return (ureg->psr & PsrMask) == PsrMusr; +} --- /sys/src/9/bcm/main.c Sun Jan 3 07:53:17 2016 +++ /sys/src/9/bcm/main.c Sun Jan 3 07:53:18 2016 @@ -603,9 +603,3 @@ delay(1000); archreboot(); } - -int -cmpswap(long *addr, long old, long new) -{ - return cas32(addr, old, new); -}