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