diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-11-04 16:00:32 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-11-04 16:00:32 +0100 |
commit | 89c659d80b91170a20157119975b19492c33a1dd (patch) | |
tree | edc823e2c47e5b4a98cfd658bc0ac97b0009dee5 /sys/src/9/bcm/arch.c | |
parent | dd82b657c0a92a5e8f2d3df6c7ca3ae83403ce91 (diff) |
bcm: fix mysterious core clock resets under SMP (thanks richard miller)
reference: https://github.com/raspberrypi/firmware/issues/542
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);
/*
* Prevent the following scenario:
* pX sleeps on cpuA, leaving its page tables in mmul1
* 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 mmul1 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);
}
Diffstat (limited to 'sys/src/9/bcm/arch.c')
-rw-r--r-- | sys/src/9/bcm/arch.c | 204 |
1 files changed, 203 insertions, 1 deletions
diff --git a/sys/src/9/bcm/arch.c b/sys/src/9/bcm/arch.c index 22d63fb43..baedbbb27 100644 --- a/sys/src/9/bcm/arch.c +++ b/sys/src/9/bcm/arch.c @@ -1 +1,203 @@ -#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 <tos.h> +#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 sysfile.c + */ +void +evenaddr(uintptr addr) +{ + 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 = t + 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); + + cycles(&p->kentry); + p->pcycles = -p->kentry; +} + +void +procfork(Proc* p) +{ + p->kentry = up->kentry; + p->pcycles = -p->kentry; + + fpuprocfork(p); +} + +/* + * Save the mach dependent part of the process state. + */ +void +procsave(Proc* p) +{ + uvlong t; + + cycles(&t); + p->pcycles += t; + p->kentry -= t; + +// TODO: save and restore VFPv3 FP state once 5[cal] know the new registers. + fpuprocsave(p); + + /* + * Prevent the following scenario: + * pX sleeps on cpuA, leaving its page tables in mmul1 + * 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 mmul1 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); +} + +void +procrestore(Proc* p) +{ + uvlong t; + + if(p->kp) + return; + cycles(&t); + p->pcycles -= t; + p->kentry += t; + + fpuprocrestore(p); +} + +int +userureg(Ureg* ureg) +{ + return (ureg->psr & PsrMask) == PsrMusr; +} + +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; +} |