xref: /plan9-contrib/sys/src/9/bcm/arch.c (revision 5c47fe09a0cc86dfb02c0ea4a2b6aec7eda2361f)
1*5c47fe09SDavid du Colombier #include "u.h"
2*5c47fe09SDavid du Colombier #include "../port/lib.h"
3*5c47fe09SDavid du Colombier #include "mem.h"
4*5c47fe09SDavid du Colombier #include "dat.h"
5*5c47fe09SDavid du Colombier #include "fns.h"
6*5c47fe09SDavid du Colombier #include "../port/error.h"
7*5c47fe09SDavid du Colombier 
8*5c47fe09SDavid du Colombier #include <tos.h>
9*5c47fe09SDavid du Colombier #include "ureg.h"
10*5c47fe09SDavid du Colombier 
11*5c47fe09SDavid du Colombier #include "arm.h"
12*5c47fe09SDavid du Colombier 
13*5c47fe09SDavid du Colombier /*
14*5c47fe09SDavid du Colombier  * A lot of this stuff doesn't belong here
15*5c47fe09SDavid du Colombier  * but this is a convenient dumping ground for
16*5c47fe09SDavid du Colombier  * later sorting into the appropriate buckets.
17*5c47fe09SDavid du Colombier  */
18*5c47fe09SDavid du Colombier 
19*5c47fe09SDavid du Colombier /* Give enough context in the ureg to produce a kernel stack for
20*5c47fe09SDavid du Colombier  * a sleeping process
21*5c47fe09SDavid du Colombier  */
22*5c47fe09SDavid du Colombier void
setkernur(Ureg * ureg,Proc * p)23*5c47fe09SDavid du Colombier setkernur(Ureg* ureg, Proc* p)
24*5c47fe09SDavid du Colombier {
25*5c47fe09SDavid du Colombier 	ureg->pc = p->sched.pc;
26*5c47fe09SDavid du Colombier 	ureg->sp = p->sched.sp+4;
27*5c47fe09SDavid du Colombier 	ureg->r14 = PTR2UINT(sched);
28*5c47fe09SDavid du Colombier }
29*5c47fe09SDavid du Colombier 
30*5c47fe09SDavid du Colombier /*
31*5c47fe09SDavid du Colombier  * called in syscallfmt.c, sysfile.c, sysproc.c
32*5c47fe09SDavid du Colombier  */
33*5c47fe09SDavid du Colombier void
validalign(uintptr addr,unsigned align)34*5c47fe09SDavid du Colombier validalign(uintptr addr, unsigned align)
35*5c47fe09SDavid du Colombier {
36*5c47fe09SDavid du Colombier 	/*
37*5c47fe09SDavid du Colombier 	 * Plan 9 is a 32-bit O/S, and the hardware it runs on
38*5c47fe09SDavid du Colombier 	 * does not usually have instructions which move 64-bit
39*5c47fe09SDavid du Colombier 	 * quantities directly, synthesizing the operations
40*5c47fe09SDavid du Colombier 	 * with 32-bit move instructions. Therefore, the compiler
41*5c47fe09SDavid du Colombier 	 * (and hardware) usually only enforce 32-bit alignment,
42*5c47fe09SDavid du Colombier 	 * if at all.
43*5c47fe09SDavid du Colombier 	 *
44*5c47fe09SDavid du Colombier 	 * Take this out if the architecture warrants it.
45*5c47fe09SDavid du Colombier 	 */
46*5c47fe09SDavid du Colombier 	if(align == sizeof(vlong))
47*5c47fe09SDavid du Colombier 		align = sizeof(long);
48*5c47fe09SDavid du Colombier 
49*5c47fe09SDavid du Colombier 	/*
50*5c47fe09SDavid du Colombier 	 * Check align is a power of 2, then addr alignment.
51*5c47fe09SDavid du Colombier 	 */
52*5c47fe09SDavid du Colombier 	if((align != 0 && !(align & (align-1))) && !(addr & (align-1)))
53*5c47fe09SDavid du Colombier 		return;
54*5c47fe09SDavid du Colombier 	postnote(up, 1, "sys: odd address", NDebug);
55*5c47fe09SDavid du Colombier 	error(Ebadarg);
56*5c47fe09SDavid du Colombier 	/*NOTREACHED*/
57*5c47fe09SDavid du Colombier }
58*5c47fe09SDavid du Colombier 
59*5c47fe09SDavid du Colombier /* go to user space */
60*5c47fe09SDavid du Colombier void
kexit(Ureg *)61*5c47fe09SDavid du Colombier kexit(Ureg*)
62*5c47fe09SDavid du Colombier {
63*5c47fe09SDavid du Colombier 	uvlong t;
64*5c47fe09SDavid du Colombier 	Tos *tos;
65*5c47fe09SDavid du Colombier 
66*5c47fe09SDavid du Colombier 	/* precise time accounting, kernel exit */
67*5c47fe09SDavid du Colombier 	tos = (Tos*)(USTKTOP-sizeof(Tos));
68*5c47fe09SDavid du Colombier 	cycles(&t);
69*5c47fe09SDavid du Colombier 	tos->kcycles += t - up->kentry;
70*5c47fe09SDavid du Colombier 	tos->pcycles = up->pcycles;
71*5c47fe09SDavid du Colombier 	tos->cyclefreq = m->cpuhz;
72*5c47fe09SDavid du Colombier 	tos->pid = up->pid;
73*5c47fe09SDavid du Colombier 
74*5c47fe09SDavid du Colombier 	/* make visible immediately to user proc */
75*5c47fe09SDavid du Colombier 	cachedwbinvse(tos, sizeof *tos);
76*5c47fe09SDavid du Colombier }
77*5c47fe09SDavid du Colombier 
78*5c47fe09SDavid du Colombier /*
79*5c47fe09SDavid du Colombier  *  return the userpc the last exception happened at
80*5c47fe09SDavid du Colombier  */
81*5c47fe09SDavid du Colombier uintptr
userpc(void)82*5c47fe09SDavid du Colombier userpc(void)
83*5c47fe09SDavid du Colombier {
84*5c47fe09SDavid du Colombier 	Ureg *ureg = up->dbgreg;
85*5c47fe09SDavid du Colombier 	return ureg->pc;
86*5c47fe09SDavid du Colombier }
87*5c47fe09SDavid du Colombier 
88*5c47fe09SDavid du Colombier /* This routine must save the values of registers the user is not permitted
89*5c47fe09SDavid du Colombier  * to write from devproc and then restore the saved values before returning.
90*5c47fe09SDavid du Colombier  */
91*5c47fe09SDavid du Colombier void
setregisters(Ureg * ureg,char * pureg,char * uva,int n)92*5c47fe09SDavid du Colombier setregisters(Ureg* ureg, char* pureg, char* uva, int n)
93*5c47fe09SDavid du Colombier {
94*5c47fe09SDavid du Colombier 	USED(ureg, pureg, uva, n);
95*5c47fe09SDavid du Colombier }
96*5c47fe09SDavid du Colombier 
97*5c47fe09SDavid du Colombier /*
98*5c47fe09SDavid du Colombier  *  this is the body for all kproc's
99*5c47fe09SDavid du Colombier  */
100*5c47fe09SDavid du Colombier static void
linkproc(void)101*5c47fe09SDavid du Colombier linkproc(void)
102*5c47fe09SDavid du Colombier {
103*5c47fe09SDavid du Colombier 	spllo();
104*5c47fe09SDavid du Colombier 	up->kpfun(up->kparg);
105*5c47fe09SDavid du Colombier 	pexit("kproc exiting", 0);
106*5c47fe09SDavid du Colombier }
107*5c47fe09SDavid du Colombier 
108*5c47fe09SDavid du Colombier /*
109*5c47fe09SDavid du Colombier  *  setup stack and initial PC for a new kernel proc.  This is architecture
110*5c47fe09SDavid du Colombier  *  dependent because of the starting stack location
111*5c47fe09SDavid du Colombier  */
112*5c47fe09SDavid du Colombier void
kprocchild(Proc * p,void (* func)(void *),void * arg)113*5c47fe09SDavid du Colombier kprocchild(Proc *p, void (*func)(void*), void *arg)
114*5c47fe09SDavid du Colombier {
115*5c47fe09SDavid du Colombier 	p->sched.pc = PTR2UINT(linkproc);
116*5c47fe09SDavid du Colombier 	p->sched.sp = PTR2UINT(p->kstack+KSTACK);
117*5c47fe09SDavid du Colombier 
118*5c47fe09SDavid du Colombier 	p->kpfun = func;
119*5c47fe09SDavid du Colombier 	p->kparg = arg;
120*5c47fe09SDavid du Colombier }
121*5c47fe09SDavid du Colombier 
122*5c47fe09SDavid du Colombier /*
123*5c47fe09SDavid du Colombier  *  pc output by dumpaproc
124*5c47fe09SDavid du Colombier  */
125*5c47fe09SDavid du Colombier uintptr
dbgpc(Proc * p)126*5c47fe09SDavid du Colombier dbgpc(Proc* p)
127*5c47fe09SDavid du Colombier {
128*5c47fe09SDavid du Colombier 	Ureg *ureg;
129*5c47fe09SDavid du Colombier 
130*5c47fe09SDavid du Colombier 	ureg = p->dbgreg;
131*5c47fe09SDavid du Colombier 	if(ureg == 0)
132*5c47fe09SDavid du Colombier 		return 0;
133*5c47fe09SDavid du Colombier 
134*5c47fe09SDavid du Colombier 	return ureg->pc;
135*5c47fe09SDavid du Colombier }
136*5c47fe09SDavid du Colombier 
137*5c47fe09SDavid du Colombier /*
138*5c47fe09SDavid du Colombier  *  set mach dependent process state for a new process
139*5c47fe09SDavid du Colombier  */
140*5c47fe09SDavid du Colombier void
procsetup(Proc * p)141*5c47fe09SDavid du Colombier procsetup(Proc* p)
142*5c47fe09SDavid du Colombier {
143*5c47fe09SDavid du Colombier 	fpusysprocsetup(p);
144*5c47fe09SDavid du Colombier }
145*5c47fe09SDavid du Colombier 
146*5c47fe09SDavid du Colombier /*
147*5c47fe09SDavid du Colombier  *  Save the mach dependent part of the process state.
148*5c47fe09SDavid du Colombier  */
149*5c47fe09SDavid du Colombier void
procsave(Proc * p)150*5c47fe09SDavid du Colombier procsave(Proc* p)
151*5c47fe09SDavid du Colombier {
152*5c47fe09SDavid du Colombier 	uvlong t;
153*5c47fe09SDavid du Colombier 
154*5c47fe09SDavid du Colombier 	cycles(&t);
155*5c47fe09SDavid du Colombier 	p->pcycles += t;
156*5c47fe09SDavid du Colombier 
157*5c47fe09SDavid du Colombier // TODO: save and restore VFPv3 FP state once 5[cal] know the new registers.
158*5c47fe09SDavid du Colombier 	fpuprocsave(p);
159*5c47fe09SDavid du Colombier 	/*
160*5c47fe09SDavid du Colombier 	 * Prevent the following scenario:
161*5c47fe09SDavid du Colombier 	 *	pX sleeps on cpuA, leaving its page tables in mmul1
162*5c47fe09SDavid du Colombier 	 *	pX wakes up on cpuB, and exits, freeing its page tables
163*5c47fe09SDavid du Colombier 	 *  pY on cpuB allocates a freed page table page and overwrites with data
164*5c47fe09SDavid du Colombier 	 *  cpuA takes an interrupt, and is now running with bad page tables
165*5c47fe09SDavid du Colombier 	 * In theory this shouldn't hurt because only user address space tables
166*5c47fe09SDavid du Colombier 	 * are affected, and mmuswitch will clear mmul1 before a user process is
167*5c47fe09SDavid du Colombier 	 * dispatched.  But empirically it correlates with weird problems, eg
168*5c47fe09SDavid du Colombier 	 * resetting of the core clock at 0x4000001C which confuses local timers.
169*5c47fe09SDavid du Colombier 	 */
170*5c47fe09SDavid du Colombier 	if(conf.nmach > 1)
171*5c47fe09SDavid du Colombier 		mmuswitch(nil);
172*5c47fe09SDavid du Colombier }
173*5c47fe09SDavid du Colombier 
174*5c47fe09SDavid du Colombier void
procrestore(Proc * p)175*5c47fe09SDavid du Colombier procrestore(Proc* p)
176*5c47fe09SDavid du Colombier {
177*5c47fe09SDavid du Colombier 	uvlong t;
178*5c47fe09SDavid du Colombier 
179*5c47fe09SDavid du Colombier 	if(p->kp)
180*5c47fe09SDavid du Colombier 		return;
181*5c47fe09SDavid du Colombier 	cycles(&t);
182*5c47fe09SDavid du Colombier 	p->pcycles -= t;
183*5c47fe09SDavid du Colombier 
184*5c47fe09SDavid du Colombier 	fpuprocrestore(p);
185*5c47fe09SDavid du Colombier }
186*5c47fe09SDavid du Colombier 
187*5c47fe09SDavid du Colombier int
userureg(Ureg * ureg)188*5c47fe09SDavid du Colombier userureg(Ureg* ureg)
189*5c47fe09SDavid du Colombier {
190*5c47fe09SDavid du Colombier 	return (ureg->psr & PsrMask) == PsrMusr;
191*5c47fe09SDavid du Colombier }
192