1154abd99SDavid du Colombier #include "u.h"
2154abd99SDavid du Colombier #include "../port/lib.h"
3154abd99SDavid du Colombier #include "mem.h"
4154abd99SDavid du Colombier #include "dat.h"
5154abd99SDavid du Colombier #include "fns.h"
6154abd99SDavid du Colombier
7154abd99SDavid du Colombier #include "init.h"
8154abd99SDavid du Colombier #include "arm.h"
9154abd99SDavid du Colombier #include <pool.h>
10*23a96966SDavid du Colombier #include <tos.h>
11154abd99SDavid du Colombier
12154abd99SDavid du Colombier #include "reboot.h"
13154abd99SDavid du Colombier
14b72bcbbfSDavid du Colombier /*
15b72bcbbfSDavid du Colombier * Where configuration info is left for the loaded programme.
16b72bcbbfSDavid du Colombier * This will turn into a structure as more is done by the boot loader
17b72bcbbfSDavid du Colombier * (e.g. why parse the .ini file twice?).
18b72bcbbfSDavid du Colombier * There are 3584 bytes available at CONFADDR.
19b72bcbbfSDavid du Colombier */
20b72bcbbfSDavid du Colombier #define BOOTARGS ((char*)CONFADDR)
21b72bcbbfSDavid du Colombier #define BOOTARGSLEN (16*KiB) /* limit in devenv.c */
22ab6ce076SDavid du Colombier #define MAXCONF 64
232a6809cbSDavid du Colombier #define MAXCONFLINE 160
24ab6ce076SDavid du Colombier
25b649930dSDavid du Colombier enum {
26b649930dSDavid du Colombier Maxmem = 512*MB, /* limited by address ranges */
27b649930dSDavid du Colombier Minmem = 256*MB, /* conservative default */
28*23a96966SDavid du Colombier
29*23a96966SDavid du Colombier /* space for syscall args, return PC, top-of-stack struct */
30*23a96966SDavid du Colombier Ustkheadroom = sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
31b649930dSDavid du Colombier };
32b649930dSDavid du Colombier
33b72bcbbfSDavid du Colombier #define isascii(c) ((uchar)(c) > 0 && (uchar)(c) < 0177)
34b72bcbbfSDavid du Colombier
35154abd99SDavid du Colombier uintptr kseg0 = KZERO;
36154abd99SDavid du Colombier Mach* machaddr[MAXMACH];
37154abd99SDavid du Colombier
38154abd99SDavid du Colombier /*
39154abd99SDavid du Colombier * Option arguments from the command line.
40154abd99SDavid du Colombier * oargv[0] is the boot file.
41154abd99SDavid du Colombier * Optionsinit() is called from multiboot()
42154abd99SDavid du Colombier * or some other machine-dependent place
43154abd99SDavid du Colombier * to set it all up.
44154abd99SDavid du Colombier */
45154abd99SDavid du Colombier static int oargc;
46154abd99SDavid du Colombier static char* oargv[20];
47154abd99SDavid du Colombier static char oargb[128];
48154abd99SDavid du Colombier static int oargblen;
49154abd99SDavid du Colombier static char oenv[4096];
50154abd99SDavid du Colombier
51154abd99SDavid du Colombier static uintptr sp; /* XXX - must go - user stack of init proc */
52154abd99SDavid du Colombier
53154abd99SDavid du Colombier int vflag;
54154abd99SDavid du Colombier char debug[256];
55154abd99SDavid du Colombier
56b72bcbbfSDavid du Colombier /* store plan9.ini contents here at least until we stash them in #ec */
57ab6ce076SDavid du Colombier static char confname[MAXCONF][KNAMELEN];
582a6809cbSDavid du Colombier static char confval[MAXCONF][MAXCONFLINE];
59ab6ce076SDavid du Colombier static int nconf;
60ab6ce076SDavid du Colombier
61047f1f95SDavid du Colombier #ifdef CRYPTOSANDBOX
62047f1f95SDavid du Colombier uchar sandbox[64*1024+BY2PG];
63047f1f95SDavid du Colombier #endif
64047f1f95SDavid du Colombier
65b72bcbbfSDavid du Colombier static int
findconf(char * name)66b72bcbbfSDavid du Colombier findconf(char *name)
67b72bcbbfSDavid du Colombier {
68b72bcbbfSDavid du Colombier int i;
69b72bcbbfSDavid du Colombier
70b72bcbbfSDavid du Colombier for(i = 0; i < nconf; i++)
71b72bcbbfSDavid du Colombier if(cistrcmp(confname[i], name) == 0)
72b72bcbbfSDavid du Colombier return i;
73b72bcbbfSDavid du Colombier return -1;
74b72bcbbfSDavid du Colombier }
75b72bcbbfSDavid du Colombier
76b72bcbbfSDavid du Colombier char*
getconf(char * name)77b72bcbbfSDavid du Colombier getconf(char *name)
78b72bcbbfSDavid du Colombier {
79b72bcbbfSDavid du Colombier int i;
80b72bcbbfSDavid du Colombier
81b72bcbbfSDavid du Colombier i = findconf(name);
82b72bcbbfSDavid du Colombier if(i >= 0)
83b72bcbbfSDavid du Colombier return confval[i];
84b72bcbbfSDavid du Colombier return nil;
85b72bcbbfSDavid du Colombier }
86b72bcbbfSDavid du Colombier
87b72bcbbfSDavid du Colombier void
addconf(char * name,char * val)88b72bcbbfSDavid du Colombier addconf(char *name, char *val)
89b72bcbbfSDavid du Colombier {
90b72bcbbfSDavid du Colombier int i;
91b72bcbbfSDavid du Colombier
92b72bcbbfSDavid du Colombier i = findconf(name);
93b72bcbbfSDavid du Colombier if(i < 0){
94b72bcbbfSDavid du Colombier if(val == nil || nconf >= MAXCONF)
95b72bcbbfSDavid du Colombier return;
96b72bcbbfSDavid du Colombier i = nconf++;
97b72bcbbfSDavid du Colombier strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
98b72bcbbfSDavid du Colombier }
992a6809cbSDavid du Colombier // confval[i] = val;
1002a6809cbSDavid du Colombier strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
101b72bcbbfSDavid du Colombier }
102b72bcbbfSDavid du Colombier
103b72bcbbfSDavid du Colombier static void
writeconf(void)104b72bcbbfSDavid du Colombier writeconf(void)
105b72bcbbfSDavid du Colombier {
106b72bcbbfSDavid du Colombier char *p, *q;
107b72bcbbfSDavid du Colombier int n;
108b72bcbbfSDavid du Colombier
109b72bcbbfSDavid du Colombier p = getconfenv();
110b72bcbbfSDavid du Colombier
111b72bcbbfSDavid du Colombier if(waserror()) {
112b72bcbbfSDavid du Colombier free(p);
113b72bcbbfSDavid du Colombier nexterror();
114b72bcbbfSDavid du Colombier }
115b72bcbbfSDavid du Colombier
116b72bcbbfSDavid du Colombier /* convert to name=value\n format */
117b72bcbbfSDavid du Colombier for(q=p; *q; q++) {
118b72bcbbfSDavid du Colombier q += strlen(q);
119b72bcbbfSDavid du Colombier *q = '=';
120b72bcbbfSDavid du Colombier q += strlen(q);
121b72bcbbfSDavid du Colombier *q = '\n';
122b72bcbbfSDavid du Colombier }
123b72bcbbfSDavid du Colombier n = q - p + 1;
124b72bcbbfSDavid du Colombier if(n >= BOOTARGSLEN)
125b72bcbbfSDavid du Colombier error("kernel configuration too large");
126b72bcbbfSDavid du Colombier memmove(BOOTARGS, p, n);
127b72bcbbfSDavid du Colombier poperror();
128b72bcbbfSDavid du Colombier free(p);
129b72bcbbfSDavid du Colombier }
130b72bcbbfSDavid du Colombier
131b72bcbbfSDavid du Colombier /*
132b72bcbbfSDavid du Colombier * assumes that we have loaded our /cfg/pxe/mac file at 0x1000 with
1332a6809cbSDavid du Colombier * tftp in u-boot. no longer uses malloc, so can be called early.
134b72bcbbfSDavid du Colombier */
135b72bcbbfSDavid du Colombier static void
plan9iniinit(void)136b72bcbbfSDavid du Colombier plan9iniinit(void)
137b72bcbbfSDavid du Colombier {
138b72bcbbfSDavid du Colombier char *k, *v, *next;
139b72bcbbfSDavid du Colombier
140b72bcbbfSDavid du Colombier k = (char *)CONFADDR;
141b72bcbbfSDavid du Colombier if(!isascii(*k))
142b72bcbbfSDavid du Colombier return;
143b72bcbbfSDavid du Colombier
144b72bcbbfSDavid du Colombier for(; k && *k != '\0'; k = next) {
145b72bcbbfSDavid du Colombier if (!isascii(*k)) /* sanity check */
146b72bcbbfSDavid du Colombier break;
147b72bcbbfSDavid du Colombier next = strchr(k, '\n');
148b72bcbbfSDavid du Colombier if (next)
149b72bcbbfSDavid du Colombier *next++ = '\0';
150b72bcbbfSDavid du Colombier
151b72bcbbfSDavid du Colombier if (*k == '\0' || *k == '\n' || *k == '#')
152b72bcbbfSDavid du Colombier continue;
153b72bcbbfSDavid du Colombier v = strchr(k, '=');
154b72bcbbfSDavid du Colombier if(v == nil)
155b72bcbbfSDavid du Colombier continue; /* mal-formed line */
156b72bcbbfSDavid du Colombier *v++ = '\0';
157b72bcbbfSDavid du Colombier
1582a6809cbSDavid du Colombier addconf(k, v);
159b72bcbbfSDavid du Colombier }
160b72bcbbfSDavid du Colombier }
161b72bcbbfSDavid du Colombier
162154abd99SDavid du Colombier static void
optionsinit(char * s)163154abd99SDavid du Colombier optionsinit(char* s)
164154abd99SDavid du Colombier {
165154abd99SDavid du Colombier char *o;
166154abd99SDavid du Colombier
167154abd99SDavid du Colombier o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
168154abd99SDavid du Colombier if(getenv("bootargs", o, o - oargb) != nil)
169154abd99SDavid du Colombier *(o-1) = ' ';
170154abd99SDavid du Colombier
171154abd99SDavid du Colombier oargblen = strlen(oargb);
172154abd99SDavid du Colombier oargc = tokenize(oargb, oargv, nelem(oargv)-1);
173154abd99SDavid du Colombier oargv[oargc] = nil;
174154abd99SDavid du Colombier }
175154abd99SDavid du Colombier
176154abd99SDavid du Colombier char*
getenv(char * name,char * buf,int n)177154abd99SDavid du Colombier getenv(char* name, char* buf, int n)
178154abd99SDavid du Colombier {
179154abd99SDavid du Colombier char *e, *p, *q;
180154abd99SDavid du Colombier
181154abd99SDavid du Colombier p = oenv;
182154abd99SDavid du Colombier while(*p != 0){
183154abd99SDavid du Colombier if((e = strchr(p, '=')) == nil)
184154abd99SDavid du Colombier break;
185154abd99SDavid du Colombier for(q = name; p < e; p++){
186154abd99SDavid du Colombier if(*p != *q)
187154abd99SDavid du Colombier break;
188154abd99SDavid du Colombier q++;
189154abd99SDavid du Colombier }
190154abd99SDavid du Colombier if(p == e && *q == 0){
191154abd99SDavid du Colombier strecpy(buf, buf+n, e+1);
192154abd99SDavid du Colombier return buf;
193154abd99SDavid du Colombier }
194154abd99SDavid du Colombier p += strlen(p)+1;
195154abd99SDavid du Colombier }
196154abd99SDavid du Colombier
197154abd99SDavid du Colombier return nil;
198154abd99SDavid du Colombier }
199154abd99SDavid du Colombier
2005e27dea9SDavid du Colombier #include "io.h"
201154abd99SDavid du Colombier
202154abd99SDavid du Colombier typedef struct Spiregs Spiregs;
203154abd99SDavid du Colombier struct Spiregs {
204154abd99SDavid du Colombier ulong ictl; /* interface ctl */
205154abd99SDavid du Colombier ulong icfg; /* interface config */
206154abd99SDavid du Colombier ulong out; /* data out */
207154abd99SDavid du Colombier ulong in; /* data in */
208154abd99SDavid du Colombier ulong ic; /* interrupt cause */
209154abd99SDavid du Colombier ulong im; /* interrupt mask */
210154abd99SDavid du Colombier ulong _pad[2];
211154abd99SDavid du Colombier ulong dwrcfg; /* direct write config */
212154abd99SDavid du Colombier ulong dwrhdr; /* direct write header */
213154abd99SDavid du Colombier };
214154abd99SDavid du Colombier
215154abd99SDavid du Colombier enum {
216154abd99SDavid du Colombier /* ictl bits */
217154abd99SDavid du Colombier Csnact = 1<<0, /* serial memory activated */
218154abd99SDavid du Colombier
219154abd99SDavid du Colombier /* icfg bits */
220154abd99SDavid du Colombier Bytelen = 1<<5, /* 2^(this_bit) bytes per transfer */
221154abd99SDavid du Colombier Dirrdcmd= 1<<10, /* flag: fast read */
222154abd99SDavid du Colombier };
223154abd99SDavid du Colombier
224154abd99SDavid du Colombier static void
dumpbytes(uchar * bp,long max)225154abd99SDavid du Colombier dumpbytes(uchar *bp, long max)
226154abd99SDavid du Colombier {
227154abd99SDavid du Colombier iprint("%#p: ", bp);
228154abd99SDavid du Colombier for (; max > 0; max--)
229154abd99SDavid du Colombier iprint("%02.2ux ", *bp++);
230154abd99SDavid du Colombier iprint("...\n");
231154abd99SDavid du Colombier }
232154abd99SDavid du Colombier
233409b3affSDavid du Colombier void archconsole(void);
234409b3affSDavid du Colombier vlong probeaddr(uintptr);
235409b3affSDavid du Colombier
236154abd99SDavid du Colombier static void
spiprobe(void)237154abd99SDavid du Colombier spiprobe(void)
238154abd99SDavid du Colombier {
2392a782499SDavid du Colombier if (0) {
2402a782499SDavid du Colombier /* generates repeated "spurious irqbridge interrupt: 00000010" on sheevaplug. */
2417365b686SDavid du Colombier Spiregs *rp = (Spiregs *)soc.spi;
242154abd99SDavid du Colombier
243409b3affSDavid du Colombier if (probeaddr(soc.spi) < 0)
244409b3affSDavid du Colombier return;
245154abd99SDavid du Colombier rp->ictl |= Csnact;
246154abd99SDavid du Colombier coherence();
247154abd99SDavid du Colombier rp->icfg |= Dirrdcmd | 3<<8; /* fast reads, 4-byte addresses */
248154abd99SDavid du Colombier rp->icfg &= ~Bytelen; /* one-byte reads */
249154abd99SDavid du Colombier coherence();
250154abd99SDavid du Colombier
251409b3affSDavid du Colombier print("spi flash ignored: ctlr %#p, data %#ux", rp, PHYSSPIFLASH);
252b649930dSDavid du Colombier mmuidmap(PHYSSPIFLASH, 1);
253409b3affSDavid du Colombier if (probeaddr(PHYSSPIFLASH) < 0)
254409b3affSDavid du Colombier print(" (no response)");
255409b3affSDavid du Colombier print(": memory reads enabled\n");
256154abd99SDavid du Colombier }
2572a782499SDavid du Colombier }
258154abd99SDavid du Colombier
259154abd99SDavid du Colombier /*
260154abd99SDavid du Colombier * entered from l.s with mmu enabled.
261154abd99SDavid du Colombier *
262154abd99SDavid du Colombier * we may have to realign the data segment; apparently 5l -H0 -R4096
263154abd99SDavid du Colombier * does not pad the text segment. on the other hand, we may have been
264154abd99SDavid du Colombier * loaded by another kernel.
265154abd99SDavid du Colombier *
266154abd99SDavid du Colombier * be careful not to touch the data segment until we know it's aligned.
267154abd99SDavid du Colombier */
268154abd99SDavid du Colombier void
main(Mach * mach)269154abd99SDavid du Colombier main(Mach* mach)
270154abd99SDavid du Colombier {
271154abd99SDavid du Colombier extern char bdata[], edata[], end[], etext[];
272154abd99SDavid du Colombier static ulong vfy = 0xcafebabe;
273154abd99SDavid du Colombier
274154abd99SDavid du Colombier m = mach;
275154abd99SDavid du Colombier if (vfy != 0xcafebabe)
276154abd99SDavid du Colombier memmove(bdata, etext, edata - bdata);
277154abd99SDavid du Colombier if (vfy != 0xcafebabe) {
278154abd99SDavid du Colombier wave('?');
279154abd99SDavid du Colombier panic("misaligned data segment");
280154abd99SDavid du Colombier }
281154abd99SDavid du Colombier memset(edata, 0, end - edata); /* zero bss */
282154abd99SDavid du Colombier vfy = 0;
283154abd99SDavid du Colombier
284154abd99SDavid du Colombier wave('9');
285154abd99SDavid du Colombier machinit();
286154abd99SDavid du Colombier archreset();
287154abd99SDavid du Colombier mmuinit();
288154abd99SDavid du Colombier
289154abd99SDavid du Colombier optionsinit("/boot/boot boot");
290154abd99SDavid du Colombier quotefmtinstall();
291154abd99SDavid du Colombier archconsole();
292b72bcbbfSDavid du Colombier wave(' ');
293154abd99SDavid du Colombier
2942a6809cbSDavid du Colombier /* want plan9.ini to be able to affect memory sizing in confinit */
2952a6809cbSDavid du Colombier plan9iniinit(); /* before we step on plan9.ini in low memory */
2962a6809cbSDavid du Colombier
297b649930dSDavid du Colombier /* set memsize before xinit */
298154abd99SDavid du Colombier confinit();
299b72bcbbfSDavid du Colombier /* xinit would print if it could */
300154abd99SDavid du Colombier xinit();
301154abd99SDavid du Colombier
302154abd99SDavid du Colombier /*
303154abd99SDavid du Colombier * Printinit will cause the first malloc call.
304154abd99SDavid du Colombier * (printinit->qopen->malloc) unless any of the
305154abd99SDavid du Colombier * above (like clockintr) do an irqenable, which
306154abd99SDavid du Colombier * will call malloc.
307154abd99SDavid du Colombier * If the system dies here it's probably due
308154abd99SDavid du Colombier * to malloc(->xalloc) not being initialised
309154abd99SDavid du Colombier * correctly, or the data segment is misaligned
310154abd99SDavid du Colombier * (it's amazing how far you can get with
311154abd99SDavid du Colombier * things like that completely broken).
312154abd99SDavid du Colombier *
313154abd99SDavid du Colombier * (Should be) boilerplate from here on.
314154abd99SDavid du Colombier */
315154abd99SDavid du Colombier trapinit();
316154abd99SDavid du Colombier clockinit();
317154abd99SDavid du Colombier
318154abd99SDavid du Colombier printinit();
319154abd99SDavid du Colombier uartkirkwoodconsole();
320ffc08dc1SDavid du Colombier /* only now can we print */
321b72bcbbfSDavid du Colombier print("from Bell Labs\n\n");
322ffc08dc1SDavid du Colombier
323047f1f95SDavid du Colombier #ifdef CRYPTOSANDBOX
324047f1f95SDavid du Colombier print("sandbox: 64K at physical %#lux, mapped to 0xf10b0000\n",
325047f1f95SDavid du Colombier PADDR((uintptr)sandbox & ~(BY2PG-1)));
326047f1f95SDavid du Colombier #endif
327047f1f95SDavid du Colombier
328154abd99SDavid du Colombier archconfinit();
329154abd99SDavid du Colombier cpuidprint();
330154abd99SDavid du Colombier timersinit();
331154abd99SDavid du Colombier
332154abd99SDavid du Colombier procinit0();
333154abd99SDavid du Colombier initseg();
334154abd99SDavid du Colombier links();
335ea9e0a24SDavid du Colombier chandevreset(); /* most devices are discovered here */
336409b3affSDavid du Colombier spiprobe();
337154abd99SDavid du Colombier
338154abd99SDavid du Colombier pageinit();
339154abd99SDavid du Colombier swapinit();
340154abd99SDavid du Colombier userinit();
341154abd99SDavid du Colombier schedinit();
342a7a38e3eSDavid du Colombier panic("schedinit returned");
343154abd99SDavid du Colombier }
344154abd99SDavid du Colombier
345154abd99SDavid du Colombier void
cpuidprint(void)346154abd99SDavid du Colombier cpuidprint(void)
347154abd99SDavid du Colombier {
348154abd99SDavid du Colombier char name[64];
349154abd99SDavid du Colombier
350154abd99SDavid du Colombier cputype2name(name, sizeof name);
351154abd99SDavid du Colombier print("cpu%d: %lldMHz ARM %s\n", m->machno, m->cpuhz/1000000, name);
352154abd99SDavid du Colombier }
353154abd99SDavid du Colombier
354154abd99SDavid du Colombier void
machinit(void)355154abd99SDavid du Colombier machinit(void)
356154abd99SDavid du Colombier {
357154abd99SDavid du Colombier memset(m, 0, sizeof(Mach));
358154abd99SDavid du Colombier m->machno = 0;
359154abd99SDavid du Colombier machaddr[m->machno] = m;
360154abd99SDavid du Colombier
361154abd99SDavid du Colombier m->ticks = 1;
362154abd99SDavid du Colombier m->perf.period = 1;
363154abd99SDavid du Colombier
364154abd99SDavid du Colombier conf.nmach = 1;
365154abd99SDavid du Colombier
366154abd99SDavid du Colombier active.machs = 1;
367154abd99SDavid du Colombier active.exiting = 0;
368154abd99SDavid du Colombier
369154abd99SDavid du Colombier up = nil;
370154abd99SDavid du Colombier }
371154abd99SDavid du Colombier
372154abd99SDavid du Colombier static void
shutdown(int ispanic)373154abd99SDavid du Colombier shutdown(int ispanic)
374154abd99SDavid du Colombier {
375154abd99SDavid du Colombier int ms, once;
376154abd99SDavid du Colombier
377154abd99SDavid du Colombier lock(&active);
378154abd99SDavid du Colombier if(ispanic)
379154abd99SDavid du Colombier active.ispanic = ispanic;
380154abd99SDavid du Colombier else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
381154abd99SDavid du Colombier active.ispanic = 0;
382154abd99SDavid du Colombier once = active.machs & (1<<m->machno);
383154abd99SDavid du Colombier active.machs &= ~(1<<m->machno);
384154abd99SDavid du Colombier active.exiting = 1;
385154abd99SDavid du Colombier unlock(&active);
386154abd99SDavid du Colombier
387154abd99SDavid du Colombier if(once)
388154abd99SDavid du Colombier iprint("cpu%d: exiting\n", m->machno);
389154abd99SDavid du Colombier spllo();
390154abd99SDavid du Colombier for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
391154abd99SDavid du Colombier delay(TK2MS(2));
392154abd99SDavid du Colombier if(active.machs == 0 && consactive() == 0)
393154abd99SDavid du Colombier break;
394154abd99SDavid du Colombier }
395154abd99SDavid du Colombier delay(1000);
396154abd99SDavid du Colombier }
397154abd99SDavid du Colombier
398154abd99SDavid du Colombier /*
399154abd99SDavid du Colombier * exit kernel either on a panic or user request
400154abd99SDavid du Colombier */
401154abd99SDavid du Colombier void
exit(int code)402154abd99SDavid du Colombier exit(int code)
403154abd99SDavid du Colombier {
404154abd99SDavid du Colombier shutdown(code);
405154abd99SDavid du Colombier splhi();
406154abd99SDavid du Colombier archreboot();
407154abd99SDavid du Colombier }
408154abd99SDavid du Colombier
409154abd99SDavid du Colombier /*
410154abd99SDavid du Colombier * the new kernel is already loaded at address `code'
411154abd99SDavid du Colombier * of size `size' and entry point `entry'.
412154abd99SDavid du Colombier */
413154abd99SDavid du Colombier void
reboot(void * entry,void * code,ulong size)414154abd99SDavid du Colombier reboot(void *entry, void *code, ulong size)
415154abd99SDavid du Colombier {
416154abd99SDavid du Colombier void (*f)(ulong, ulong, ulong);
417154abd99SDavid du Colombier
418154abd99SDavid du Colombier iprint("starting reboot...");
419b72bcbbfSDavid du Colombier writeconf();
420b72bcbbfSDavid du Colombier
421154abd99SDavid du Colombier shutdown(0);
422154abd99SDavid du Colombier
423154abd99SDavid du Colombier /*
424154abd99SDavid du Colombier * should be the only processor running now
425154abd99SDavid du Colombier */
426154abd99SDavid du Colombier
427154abd99SDavid du Colombier print("shutting down...\n");
428154abd99SDavid du Colombier delay(200);
429154abd99SDavid du Colombier
430154abd99SDavid du Colombier /* turn off buffered serial console */
431154abd99SDavid du Colombier serialoq = nil;
432154abd99SDavid du Colombier
433154abd99SDavid du Colombier /* shutdown devices */
434c8a340cdSDavid du Colombier chandevshutdown();
435154abd99SDavid du Colombier
43656713243SDavid du Colombier /* call off the dog */
43756713243SDavid du Colombier clockshutdown();
43856713243SDavid du Colombier
43956713243SDavid du Colombier splhi();
44056713243SDavid du Colombier
441154abd99SDavid du Colombier /* setup reboot trampoline function */
442154abd99SDavid du Colombier f = (void*)REBOOTADDR;
443154abd99SDavid du Colombier memmove(f, rebootcode, sizeof(rebootcode));
444b72bcbbfSDavid du Colombier cacheuwbinv();
445a7a38e3eSDavid du Colombier l2cacheuwb();
446154abd99SDavid du Colombier
447154abd99SDavid du Colombier print("rebooting...");
448154abd99SDavid du Colombier iprint("entry %#lux code %#lux size %ld\n",
449154abd99SDavid du Colombier PADDR(entry), PADDR(code), size);
450154abd99SDavid du Colombier delay(100); /* wait for uart to quiesce */
451154abd99SDavid du Colombier
452154abd99SDavid du Colombier /* off we go - never to return */
453b72bcbbfSDavid du Colombier cacheuwbinv();
454a7a38e3eSDavid du Colombier l2cacheuwb();
455154abd99SDavid du Colombier (*f)(PADDR(entry), PADDR(code), size);
456154abd99SDavid du Colombier
457154abd99SDavid du Colombier iprint("loaded kernel returned!\n");
45856713243SDavid du Colombier delay(1000);
459154abd99SDavid du Colombier archreboot();
460154abd99SDavid du Colombier }
461154abd99SDavid du Colombier
462154abd99SDavid du Colombier /*
463154abd99SDavid du Colombier * starting place for first process
464154abd99SDavid du Colombier */
465154abd99SDavid du Colombier void
init0(void)466154abd99SDavid du Colombier init0(void)
467154abd99SDavid du Colombier {
468b72bcbbfSDavid du Colombier int i;
469154abd99SDavid du Colombier char buf[2*KNAMELEN];
470154abd99SDavid du Colombier
471154abd99SDavid du Colombier assert(up != nil);
472154abd99SDavid du Colombier up->nerrlab = 0;
473154abd99SDavid du Colombier coherence();
474154abd99SDavid du Colombier spllo();
475154abd99SDavid du Colombier
476154abd99SDavid du Colombier /*
477154abd99SDavid du Colombier * These are o.k. because rootinit is null.
478154abd99SDavid du Colombier * Then early kproc's will have a root and dot.
479154abd99SDavid du Colombier */
480154abd99SDavid du Colombier up->slash = namec("#/", Atodir, 0, 0);
481154abd99SDavid du Colombier pathclose(up->slash->path);
482154abd99SDavid du Colombier up->slash->path = newpath("/");
483154abd99SDavid du Colombier up->dot = cclone(up->slash);
484154abd99SDavid du Colombier
485c8a340cdSDavid du Colombier chandevinit();
486154abd99SDavid du Colombier
487154abd99SDavid du Colombier if(!waserror()){
488154abd99SDavid du Colombier snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
489154abd99SDavid du Colombier ksetenv("terminal", buf, 0);
490154abd99SDavid du Colombier ksetenv("cputype", "arm", 0);
491154abd99SDavid du Colombier if(cpuserver)
492154abd99SDavid du Colombier ksetenv("service", "cpu", 0);
493154abd99SDavid du Colombier else
494154abd99SDavid du Colombier ksetenv("service", "terminal", 0);
495154abd99SDavid du Colombier
496b72bcbbfSDavid du Colombier /* convert plan9.ini variables to #e and #ec */
497b72bcbbfSDavid du Colombier for(i = 0; i < nconf; i++) {
498b72bcbbfSDavid du Colombier ksetenv(confname[i], confval[i], 0);
499b72bcbbfSDavid du Colombier ksetenv(confname[i], confval[i], 1);
500b72bcbbfSDavid du Colombier }
501154abd99SDavid du Colombier poperror();
502154abd99SDavid du Colombier }
503154abd99SDavid du Colombier kproc("alarm", alarmkproc, 0);
504154abd99SDavid du Colombier
505154abd99SDavid du Colombier touser(sp);
506154abd99SDavid du Colombier }
507154abd99SDavid du Colombier
508154abd99SDavid du Colombier static void
bootargs(uintptr base)509154abd99SDavid du Colombier bootargs(uintptr base)
510154abd99SDavid du Colombier {
511154abd99SDavid du Colombier int i;
512154abd99SDavid du Colombier ulong ssize;
513154abd99SDavid du Colombier char **av, *p;
514154abd99SDavid du Colombier
515154abd99SDavid du Colombier /*
516154abd99SDavid du Colombier * Push the boot args onto the stack.
517154abd99SDavid du Colombier * The initial value of the user stack must be such
518154abd99SDavid du Colombier * that the total used is larger than the maximum size
519154abd99SDavid du Colombier * of the argument list checked in syscall.
520154abd99SDavid du Colombier */
521154abd99SDavid du Colombier i = oargblen+1;
522*23a96966SDavid du Colombier p = UINT2PTR(STACKALIGN(base + BY2PG - Ustkheadroom - i));
523154abd99SDavid du Colombier memmove(p, oargb, i);
524154abd99SDavid du Colombier
525154abd99SDavid du Colombier /*
526154abd99SDavid du Colombier * Now push argc and the argv pointers.
527154abd99SDavid du Colombier * This isn't strictly correct as the code jumped to by
528154abd99SDavid du Colombier * touser in init9.s calls startboot (port/initcode.c) which
529154abd99SDavid du Colombier * expects arguments
530154abd99SDavid du Colombier * startboot(char *argv0, char **argv)
531154abd99SDavid du Colombier * not the usual (int argc, char* argv[]), but argv0 is
532154abd99SDavid du Colombier * unused so it doesn't matter (at the moment...).
533154abd99SDavid du Colombier */
534154abd99SDavid du Colombier av = (char**)(p - (oargc+2)*sizeof(char*));
535b1c4f505SDavid du Colombier ssize = base + BY2PG - PTR2UINT(av);
536154abd99SDavid du Colombier *av++ = (char*)oargc;
537154abd99SDavid du Colombier for(i = 0; i < oargc; i++)
538154abd99SDavid du Colombier *av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
539154abd99SDavid du Colombier *av = nil;
540154abd99SDavid du Colombier
541154abd99SDavid du Colombier /*
542154abd99SDavid du Colombier * Leave space for the return PC of the
543154abd99SDavid du Colombier * caller of initcode.
544154abd99SDavid du Colombier */
545154abd99SDavid du Colombier sp = USTKTOP - ssize - sizeof(void*);
546154abd99SDavid du Colombier }
547154abd99SDavid du Colombier
548154abd99SDavid du Colombier /*
549154abd99SDavid du Colombier * create the first process
550154abd99SDavid du Colombier */
551154abd99SDavid du Colombier void
userinit(void)552154abd99SDavid du Colombier userinit(void)
553154abd99SDavid du Colombier {
554154abd99SDavid du Colombier Proc *p;
555154abd99SDavid du Colombier Segment *s;
556154abd99SDavid du Colombier KMap *k;
557154abd99SDavid du Colombier Page *pg;
558154abd99SDavid du Colombier
559154abd99SDavid du Colombier /* no processes yet */
560154abd99SDavid du Colombier up = nil;
561154abd99SDavid du Colombier
562154abd99SDavid du Colombier p = newproc();
563154abd99SDavid du Colombier p->pgrp = newpgrp();
564154abd99SDavid du Colombier p->egrp = smalloc(sizeof(Egrp));
565154abd99SDavid du Colombier p->egrp->ref = 1;
566154abd99SDavid du Colombier p->fgrp = dupfgrp(nil);
567154abd99SDavid du Colombier p->rgrp = newrgrp();
568154abd99SDavid du Colombier p->procmode = 0640;
569154abd99SDavid du Colombier
570154abd99SDavid du Colombier kstrdup(&eve, "");
571154abd99SDavid du Colombier kstrdup(&p->text, "*init*");
572154abd99SDavid du Colombier kstrdup(&p->user, eve);
573154abd99SDavid du Colombier
574154abd99SDavid du Colombier /*
575154abd99SDavid du Colombier * Kernel Stack
576154abd99SDavid du Colombier */
577154abd99SDavid du Colombier p->sched.pc = PTR2UINT(init0);
578154abd99SDavid du Colombier p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
579154abd99SDavid du Colombier p->sched.sp = STACKALIGN(p->sched.sp);
580154abd99SDavid du Colombier
581154abd99SDavid du Colombier /*
582154abd99SDavid du Colombier * User Stack
583154abd99SDavid du Colombier *
584154abd99SDavid du Colombier * Technically, newpage can't be called here because it
585154abd99SDavid du Colombier * should only be called when in a user context as it may
586154abd99SDavid du Colombier * try to sleep if there are no pages available, but that
587154abd99SDavid du Colombier * shouldn't be the case here.
588154abd99SDavid du Colombier */
589154abd99SDavid du Colombier s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
590154abd99SDavid du Colombier p->seg[SSEG] = s;
591154abd99SDavid du Colombier pg = newpage(1, 0, USTKTOP-BY2PG);
592154abd99SDavid du Colombier segpage(s, pg);
593154abd99SDavid du Colombier k = kmap(pg);
594154abd99SDavid du Colombier bootargs(VA(k));
595154abd99SDavid du Colombier kunmap(k);
596154abd99SDavid du Colombier
597154abd99SDavid du Colombier /*
598154abd99SDavid du Colombier * Text
599154abd99SDavid du Colombier */
600154abd99SDavid du Colombier s = newseg(SG_TEXT, UTZERO, 1);
601154abd99SDavid du Colombier s->flushme++;
602154abd99SDavid du Colombier p->seg[TSEG] = s;
603154abd99SDavid du Colombier pg = newpage(1, 0, UTZERO);
604154abd99SDavid du Colombier memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
605154abd99SDavid du Colombier segpage(s, pg);
606154abd99SDavid du Colombier k = kmap(s->map[0]->pages[0]);
607154abd99SDavid du Colombier memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
608154abd99SDavid du Colombier kunmap(k);
609154abd99SDavid du Colombier
610154abd99SDavid du Colombier ready(p);
611154abd99SDavid du Colombier }
612154abd99SDavid du Colombier
613154abd99SDavid du Colombier Conf conf; /* XXX - must go - gag */
614154abd99SDavid du Colombier
615b649930dSDavid du Colombier Confmem sheevamem[nelem(conf.mem)] = {
616154abd99SDavid du Colombier /*
617154abd99SDavid du Colombier * Memory available to Plan 9:
61806f6463aSDavid du Colombier * the 8K is reserved for ethernet dma access violations to scribble on.
619154abd99SDavid du Colombier */
62063c59e25SDavid du Colombier { .base = PHYSDRAM, .limit = PHYSDRAM + Maxmem - 8*1024, },
621154abd99SDavid du Colombier };
622b649930dSDavid du Colombier ulong memsize = Maxmem;
623b649930dSDavid du Colombier
624b649930dSDavid du Colombier static int
gotmem(uintptr sz)625b649930dSDavid du Colombier gotmem(uintptr sz)
626b649930dSDavid du Colombier {
627b649930dSDavid du Colombier uintptr addr;
628b649930dSDavid du Colombier
629b649930dSDavid du Colombier addr = PHYSDRAM + sz - MB;
630b649930dSDavid du Colombier mmuidmap(addr, 1);
631b649930dSDavid du Colombier if (probeaddr(addr) >= 0) {
632b649930dSDavid du Colombier memsize = sz;
633b649930dSDavid du Colombier return 0;
634b649930dSDavid du Colombier }
635b649930dSDavid du Colombier return -1;
636b649930dSDavid du Colombier }
637154abd99SDavid du Colombier
638154abd99SDavid du Colombier void
confinit(void)639154abd99SDavid du Colombier confinit(void)
640154abd99SDavid du Colombier {
641154abd99SDavid du Colombier int i;
642154abd99SDavid du Colombier ulong kpages;
643154abd99SDavid du Colombier uintptr pa;
644b649930dSDavid du Colombier char *p;
645154abd99SDavid du Colombier
646154abd99SDavid du Colombier /*
647154abd99SDavid du Colombier * Copy the physical memory configuration to Conf.mem.
648154abd99SDavid du Colombier */
649154abd99SDavid du Colombier if(nelem(sheevamem) > nelem(conf.mem)){
650154abd99SDavid du Colombier iprint("memory configuration botch\n");
651154abd99SDavid du Colombier exit(1);
652154abd99SDavid du Colombier }
653b649930dSDavid du Colombier if((p = getconf("*maxmem")) != nil) {
654b649930dSDavid du Colombier memsize = strtoul(p, 0, 0) - PHYSDRAM;
655b649930dSDavid du Colombier if (memsize < 16*MB) /* sanity */
656b649930dSDavid du Colombier memsize = 16*MB;
657b649930dSDavid du Colombier }
658b649930dSDavid du Colombier
659b649930dSDavid du Colombier /*
660b649930dSDavid du Colombier * see if all that memory exists; if not, find out how much does.
661b649930dSDavid du Colombier * trapinit must have been called first.
662b649930dSDavid du Colombier */
663b649930dSDavid du Colombier if (gotmem(memsize) < 0 && gotmem(256*MB) < 0 && gotmem(128*MB) < 0) {
664b649930dSDavid du Colombier iprint("can't find any memory, assuming %dMB\n", Minmem / MB);
665b649930dSDavid du Colombier memsize = Minmem;
666b649930dSDavid du Colombier }
667b649930dSDavid du Colombier
668b649930dSDavid du Colombier sheevamem[0].limit = PHYSDRAM + memsize - 8*1024;
669154abd99SDavid du Colombier memmove(conf.mem, sheevamem, sizeof(sheevamem));
670154abd99SDavid du Colombier
671154abd99SDavid du Colombier conf.npage = 0;
672154abd99SDavid du Colombier pa = PADDR(PGROUND(PTR2UINT(end)));
673154abd99SDavid du Colombier
674154abd99SDavid du Colombier /*
675154abd99SDavid du Colombier * we assume that the kernel is at the beginning of one of the
676154abd99SDavid du Colombier * contiguous chunks of memory and fits therein.
677154abd99SDavid du Colombier */
678154abd99SDavid du Colombier for(i=0; i<nelem(conf.mem); i++){
679154abd99SDavid du Colombier /* take kernel out of allocatable space */
680154abd99SDavid du Colombier if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
681154abd99SDavid du Colombier conf.mem[i].base = pa;
682154abd99SDavid du Colombier
683154abd99SDavid du Colombier conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
684154abd99SDavid du Colombier conf.npage += conf.mem[i].npage;
685154abd99SDavid du Colombier }
686154abd99SDavid du Colombier
687154abd99SDavid du Colombier conf.upages = (conf.npage*90)/100;
688154abd99SDavid du Colombier conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
689154abd99SDavid du Colombier
690154abd99SDavid du Colombier /* only one processor */
691154abd99SDavid du Colombier conf.nmach = 1;
692154abd99SDavid du Colombier
693154abd99SDavid du Colombier /* set up other configuration parameters */
694154abd99SDavid du Colombier conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
695154abd99SDavid du Colombier if(cpuserver)
696154abd99SDavid du Colombier conf.nproc *= 3;
697154abd99SDavid du Colombier if(conf.nproc > 2000)
698154abd99SDavid du Colombier conf.nproc = 2000;
699154abd99SDavid du Colombier conf.nswap = conf.npage*3;
700154abd99SDavid du Colombier conf.nswppo = 4096;
701154abd99SDavid du Colombier conf.nimage = 200;
702154abd99SDavid du Colombier
703154abd99SDavid du Colombier conf.copymode = 0; /* copy on write */
704154abd99SDavid du Colombier
705154abd99SDavid du Colombier /*
706154abd99SDavid du Colombier * Guess how much is taken by the large permanent
707154abd99SDavid du Colombier * datastructures. Mntcache and Mntrpc are not accounted for
708154abd99SDavid du Colombier * (probably ~300KB).
709154abd99SDavid du Colombier */
710154abd99SDavid du Colombier kpages = conf.npage - conf.upages;
711154abd99SDavid du Colombier kpages *= BY2PG;
712154abd99SDavid du Colombier kpages -= conf.upages*sizeof(Page)
713154abd99SDavid du Colombier + conf.nproc*sizeof(Proc)
714154abd99SDavid du Colombier + conf.nimage*sizeof(Image)
715154abd99SDavid du Colombier + conf.nswap
716154abd99SDavid du Colombier + conf.nswppo*sizeof(Page);
717154abd99SDavid du Colombier mainmem->maxsize = kpages;
718154abd99SDavid du Colombier if(!cpuserver)
719154abd99SDavid du Colombier /*
720154abd99SDavid du Colombier * give terminals lots of image memory, too; the dynamic
721154abd99SDavid du Colombier * allocation will balance the load properly, hopefully.
722154abd99SDavid du Colombier * be careful with 32-bit overflow.
723154abd99SDavid du Colombier */
724154abd99SDavid du Colombier imagmem->maxsize = kpages;
725154abd99SDavid du Colombier }
726154abd99SDavid du Colombier
727154abd99SDavid du Colombier int
cmpswap(long * addr,long old,long new)728154abd99SDavid du Colombier cmpswap(long *addr, long old, long new)
729154abd99SDavid du Colombier {
730154abd99SDavid du Colombier return cas32(addr, old, new);
731154abd99SDavid du Colombier }
732