changeset 6857: | 1d3c6cec5137 |
---|---|
parent 6856: | 0df717a3b0a1 |
child 6858: | 9343c5adab20 |
child 6859: | f1f3e27f4831 |
author: | cinap_lenrek@felloff.net |
date: | Sun, 04 Nov 2018 16:00:32 +0100 |
files: | sys/src/9/bcm/arch.c |
description: | 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); } |
1.1--- a/sys/src/9/bcm/arch.c 1.2+++ b/sys/src/9/bcm/arch.c 1.3@@ -1,1 +1,203 @@ 1.4-#include "../omap/arch.c" 1.5+#include "u.h" 1.6+#include "../port/lib.h" 1.7+#include "mem.h" 1.8+#include "dat.h" 1.9+#include "fns.h" 1.10+#include "../port/error.h" 1.11+ 1.12+#include <tos.h> 1.13+#include "ureg.h" 1.14+ 1.15+#include "arm.h" 1.16+ 1.17+/* 1.18+ * A lot of this stuff doesn't belong here 1.19+ * but this is a convenient dumping ground for 1.20+ * later sorting into the appropriate buckets. 1.21+ */ 1.22+ 1.23+/* Give enough context in the ureg to produce a kernel stack for 1.24+ * a sleeping process 1.25+ */ 1.26+void 1.27+setkernur(Ureg* ureg, Proc* p) 1.28+{ 1.29+ ureg->pc = p->sched.pc; 1.30+ ureg->sp = p->sched.sp+4; 1.31+ ureg->r14 = PTR2UINT(sched); 1.32+} 1.33+ 1.34+/* 1.35+ * called in sysfile.c 1.36+ */ 1.37+void 1.38+evenaddr(uintptr addr) 1.39+{ 1.40+ if(addr & 3){ 1.41+ postnote(up, 1, "sys: odd address", NDebug); 1.42+ error(Ebadarg); 1.43+ } 1.44+} 1.45+ 1.46+/* go to user space */ 1.47+void 1.48+kexit(Ureg*) 1.49+{ 1.50+ uvlong t; 1.51+ Tos *tos; 1.52+ 1.53+ /* precise time accounting, kernel exit */ 1.54+ tos = (Tos*)(USTKTOP-sizeof(Tos)); 1.55+ cycles(&t); 1.56+ tos->kcycles += t - up->kentry; 1.57+ tos->pcycles = t + up->pcycles; 1.58+ tos->cyclefreq = m->cpuhz; 1.59+ tos->pid = up->pid; 1.60+ 1.61+ /* make visible immediately to user proc */ 1.62+ cachedwbinvse(tos, sizeof *tos); 1.63+} 1.64+ 1.65+/* 1.66+ * return the userpc the last exception happened at 1.67+ */ 1.68+uintptr 1.69+userpc(void) 1.70+{ 1.71+ Ureg *ureg = up->dbgreg; 1.72+ return ureg->pc; 1.73+} 1.74+ 1.75+/* This routine must save the values of registers the user is not permitted 1.76+ * to write from devproc and then restore the saved values before returning. 1.77+ */ 1.78+void 1.79+setregisters(Ureg* ureg, char* pureg, char* uva, int n) 1.80+{ 1.81+ USED(ureg, pureg, uva, n); 1.82+} 1.83+ 1.84+/* 1.85+ * this is the body for all kproc's 1.86+ */ 1.87+static void 1.88+linkproc(void) 1.89+{ 1.90+ spllo(); 1.91+ up->kpfun(up->kparg); 1.92+ pexit("kproc exiting", 0); 1.93+} 1.94+ 1.95+/* 1.96+ * setup stack and initial PC for a new kernel proc. This is architecture 1.97+ * dependent because of the starting stack location 1.98+ */ 1.99+void 1.100+kprocchild(Proc *p, void (*func)(void*), void *arg) 1.101+{ 1.102+ p->sched.pc = PTR2UINT(linkproc); 1.103+ p->sched.sp = PTR2UINT(p->kstack+KSTACK); 1.104+ 1.105+ p->kpfun = func; 1.106+ p->kparg = arg; 1.107+} 1.108+ 1.109+/* 1.110+ * pc output by dumpaproc 1.111+ */ 1.112+uintptr 1.113+dbgpc(Proc* p) 1.114+{ 1.115+ Ureg *ureg; 1.116+ 1.117+ ureg = p->dbgreg; 1.118+ if(ureg == 0) 1.119+ return 0; 1.120+ 1.121+ return ureg->pc; 1.122+} 1.123+ 1.124+/* 1.125+ * set mach dependent process state for a new process 1.126+ */ 1.127+void 1.128+procsetup(Proc* p) 1.129+{ 1.130+ fpusysprocsetup(p); 1.131+ 1.132+ cycles(&p->kentry); 1.133+ p->pcycles = -p->kentry; 1.134+} 1.135+ 1.136+void 1.137+procfork(Proc* p) 1.138+{ 1.139+ p->kentry = up->kentry; 1.140+ p->pcycles = -p->kentry; 1.141+ 1.142+ fpuprocfork(p); 1.143+} 1.144+ 1.145+/* 1.146+ * Save the mach dependent part of the process state. 1.147+ */ 1.148+void 1.149+procsave(Proc* p) 1.150+{ 1.151+ uvlong t; 1.152+ 1.153+ cycles(&t); 1.154+ p->pcycles += t; 1.155+ p->kentry -= t; 1.156+ 1.157+// TODO: save and restore VFPv3 FP state once 5[cal] know the new registers. 1.158+ fpuprocsave(p); 1.159+ 1.160+ /* 1.161+ * Prevent the following scenario: 1.162+ * pX sleeps on cpuA, leaving its page tables in mmul1 1.163+ * pX wakes up on cpuB, and exits, freeing its page tables 1.164+ * pY on cpuB allocates a freed page table page and overwrites with data 1.165+ * cpuA takes an interrupt, and is now running with bad page tables 1.166+ * In theory this shouldn't hurt because only user address space tables 1.167+ * are affected, and mmuswitch will clear mmul1 before a user process is 1.168+ * dispatched. But empirically it correlates with weird problems, eg 1.169+ * resetting of the core clock at 0x4000001C which confuses local timers. 1.170+ */ 1.171+ if(conf.nmach > 1) 1.172+ mmuswitch(nil); 1.173+} 1.174+ 1.175+void 1.176+procrestore(Proc* p) 1.177+{ 1.178+ uvlong t; 1.179+ 1.180+ if(p->kp) 1.181+ return; 1.182+ cycles(&t); 1.183+ p->pcycles -= t; 1.184+ p->kentry += t; 1.185+ 1.186+ fpuprocrestore(p); 1.187+} 1.188+ 1.189+int 1.190+userureg(Ureg* ureg) 1.191+{ 1.192+ return (ureg->psr & PsrMask) == PsrMusr; 1.193+} 1.194+ 1.195+int 1.196+cas32(void* addr, u32int old, u32int new) 1.197+{ 1.198+ int r, s; 1.199+ 1.200+ s = splhi(); 1.201+ if(r = (*(u32int*)addr == old)) 1.202+ *(u32int*)addr = new; 1.203+ splx(s); 1.204+ if (r) 1.205+ coherence(); 1.206+ return r; 1.207+}