]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/kw/main.c
vmx: clean up mksegment, memset only if segment existed (devsegment clears new ones)
[plan9front.git] / sys / src / 9 / kw / main.c
1 #include "u.h"
2 #include "tos.h"
3 #include "../port/lib.h"
4 #include "mem.h"
5 #include "dat.h"
6 #include "fns.h"
7
8 #include "arm.h"
9 #include <pool.h>
10
11 #include "rebootcode.i"
12
13 /*
14  * Where configuration info is left for the loaded programme.
15  * This will turn into a structure as more is done by the boot loader
16  * (e.g. why parse the .ini file twice?).
17  * There are 3584 bytes available at CONFADDR.
18  */
19 #define BOOTARGS        ((char*)CONFADDR)
20 #define BOOTARGSLEN     (16*KiB)                /* limit in devenv.c */
21 #define MAXCONF         64
22 #define MAXCONFLINE     160
23
24 #define isascii(c) ((uchar)(c) > 0 && (uchar)(c) < 0177)
25
26 uintptr kseg0 = KZERO;
27 Mach* machaddr[MAXMACH];
28
29 int vflag;
30 char debug[256];
31
32 /* store plan9.ini contents here at least until we stash them in #ec */
33 static char confname[MAXCONF][KNAMELEN];
34 static char confval[MAXCONF][MAXCONFLINE];
35 static int nconf;
36
37 #ifdef CRYPTOSANDBOX
38 uchar sandbox[64*1024+BY2PG];
39 #endif
40
41 static int
42 findconf(char *name)
43 {
44         int i;
45
46         for(i = 0; i < nconf; i++)
47                 if(cistrcmp(confname[i], name) == 0)
48                         return i;
49         return -1;
50 }
51
52 char*
53 getconf(char *name)
54 {
55         int i;
56
57         i = findconf(name);
58         if(i >= 0)
59                 return confval[i];
60         return nil;
61 }
62
63 void
64 addconf(char *name, char *val)
65 {
66         int i;
67
68         i = findconf(name);
69         if(i < 0){
70                 if(val == nil || nconf >= MAXCONF)
71                         return;
72                 i = nconf++;
73                 strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
74         }
75 //      confval[i] = val;
76         strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
77 }
78
79 static void
80 writeconf(void)
81 {
82         char *p, *q;
83         int n;
84
85         p = getconfenv();
86
87         if(waserror()) {
88                 free(p);
89                 nexterror();
90         }
91
92         /* convert to name=value\n format */
93         for(q=p; *q; q++) {
94                 q += strlen(q);
95                 *q = '=';
96                 q += strlen(q);
97                 *q = '\n';
98         }
99         n = q - p + 1;
100         if(n >= BOOTARGSLEN)
101                 error("kernel configuration too large");
102         memmove(BOOTARGS, p, n);
103         poperror();
104         free(p);
105 }
106
107 /*
108  * assumes that we have loaded our /cfg/pxe/mac file at 0x1000 with
109  * tftp in u-boot.  no longer uses malloc, so can be called early.
110  */
111 static void
112 plan9iniinit(void)
113 {
114         char *k, *v, *next;
115
116         k = (char *)CONFADDR;
117         if(!isascii(*k))
118                 return;
119
120         for(; k && *k != '\0'; k = next) {
121                 if (!isascii(*k))               /* sanity check */
122                         break;
123                 next = strchr(k, '\n');
124                 if (next)
125                         *next++ = '\0';
126
127                 if (*k == '\0' || *k == '\n' || *k == '#')
128                         continue;
129                 v = strchr(k, '=');
130                 if(v == nil)
131                         continue;               /* mal-formed line */
132                 *v++ = '\0';
133
134                 addconf(k, v);
135         }
136 }
137
138 #include "io.h"
139
140 typedef struct Spiregs Spiregs;
141 struct Spiregs {
142         ulong   ictl;           /* interface ctl */
143         ulong   icfg;           /* interface config */
144         ulong   out;            /* data out */
145         ulong   in;             /* data in */
146         ulong   ic;             /* interrupt cause */
147         ulong   im;             /* interrupt mask */
148         ulong   _pad[2];
149         ulong   dwrcfg;         /* direct write config */
150         ulong   dwrhdr;         /* direct write header */
151 };
152
153 enum {
154         /* ictl bits */
155         Csnact  = 1<<0,         /* serial memory activated */
156
157         /* icfg bits */
158         Bytelen = 1<<5,         /* 2^(this_bit) bytes per transfer */
159         Dirrdcmd= 1<<10,        /* flag: fast read */
160 };
161
162 static void
163 dumpbytes(uchar *bp, long max)
164 {
165         iprint("%#p: ", bp);
166         for (; max > 0; max--)
167                 iprint("%02.2ux ", *bp++);
168         iprint("...\n");
169 }
170
171 static void
172 spiprobe(void)
173 {
174         Spiregs *rp = (Spiregs *)soc.spi;
175
176         rp->ictl |= Csnact;
177         coherence();
178         rp->icfg |= Dirrdcmd | 3<<8;    /* fast reads, 4-byte addresses */
179         rp->icfg &= ~Bytelen;           /* one-byte reads */
180         coherence();
181
182 //      print("spi flash at %#ux: memory reads enabled\n", PHYSSPIFLASH);
183 }
184
185 void    archconsole(void);
186
187 /* dummy for usb */
188 int
189 isaconfig(char *, int, ISAConf *)
190 {
191         return 0;
192 }
193
194 /*
195  * entered from l.s with mmu enabled.
196  *
197  * we may have to realign the data segment; apparently 5l -H0 -R4096
198  * does not pad the text segment.  on the other hand, we may have been
199  * loaded by another kernel.
200  *
201  * be careful not to touch the data segment until we know it's aligned.
202  */
203 void
204 main(Mach* mach)
205 {
206         extern char bdata[], edata[], end[], etext[];
207         static ulong vfy = 0xcafebabe;
208
209         m = mach;
210         if (vfy != 0xcafebabe)
211                 memmove(bdata, etext, edata - bdata);
212         if (vfy != 0xcafebabe) {
213                 wave('?');
214                 panic("misaligned data segment");
215         }
216         memset(edata, 0, end - edata);          /* zero bss */
217         vfy = 0;
218
219 wave('9');
220         machinit();
221         archreset();
222         mmuinit();
223
224         quotefmtinstall();
225         archconsole();
226 wave(' ');
227
228         /* want plan9.ini to be able to affect memory sizing in confinit */
229         plan9iniinit();         /* before we step on plan9.ini in low memory */
230
231         confinit();
232         /* xinit would print if it could */
233         xinit();
234
235         /*
236          * Printinit will cause the first malloc call.
237          * (printinit->qopen->malloc) unless any of the
238          * above (like clockintr) do an irqenable, which
239          * will call malloc.
240          * If the system dies here it's probably due
241          * to malloc(->xalloc) not being initialised
242          * correctly, or the data segment is misaligned
243          * (it's amazing how far you can get with
244          * things like that completely broken).
245          *
246          * (Should be) boilerplate from here on.
247          */
248         trapinit();
249         clockinit();
250
251         printinit();
252         uartkirkwoodconsole();
253         /* only now can we print */
254         print("from Bell Labs\n\n");
255
256 #ifdef CRYPTOSANDBOX
257         print("sandbox: 64K at physical %#lux, mapped to 0xf10b0000\n",
258                 PADDR((uintptr)sandbox & ~(BY2PG-1)));
259 #endif
260
261         archconfinit();
262         cpuidprint();
263         timersinit();
264
265         procinit0();
266         initseg();
267         links();
268         chandevreset();                 /* most devices are discovered here */
269
270         pageinit();
271         userinit();
272         schedinit();
273         panic("schedinit returned");
274 }
275
276 void
277 cpuidprint(void)
278 {
279         char name[64];
280
281         cputype2name(name, sizeof name);
282         print("cpu%d: %lldMHz ARM %s\n", m->machno, m->cpuhz/1000000, name);
283 }
284
285 void
286 machinit(void)
287 {
288         memset(m, 0, sizeof(Mach));
289         m->machno = 0;
290         machaddr[m->machno] = m;
291
292         m->ticks = 1;
293         m->perf.period = 1;
294
295         conf.nmach = 1;
296
297         active.machs[0] = 1;
298         active.exiting = 0;
299
300         up = nil;
301 }
302
303 /*
304  *  exit kernel either on a panic or user request
305  */
306 void
307 exit(int)
308 {
309         cpushutdown();
310         splhi();
311         archreboot();
312 }
313
314 /*
315  * the new kernel is already loaded at address `code'
316  * of size `size' and entry point `entry'.
317  */
318 void
319 reboot(void *entry, void *code, ulong size)
320 {
321         void (*f)(ulong, ulong, ulong);
322
323         writeconf();
324         cpushutdown();
325
326         /* turn off buffered serial console */
327         serialoq = nil;
328
329         /* shutdown devices */
330         chandevshutdown();
331
332         /* call off the dog */
333         clockshutdown();
334
335         splhi();
336
337         /* setup reboot trampoline function */
338         f = (void*)REBOOTADDR;
339         memmove(f, rebootcode, sizeof(rebootcode));
340         cacheuwbinv();
341         l2cacheuwb();
342
343         /* off we go - never to return */
344         cacheuwbinv();
345         l2cacheuwb();
346         (*f)(PADDR(entry), PADDR(code), size);
347 }
348
349 /*
350  *  starting place for first process
351  */
352 void
353 init0(void)
354 {
355         char buf[2*KNAMELEN], **sp;
356         int i;
357
358         chandevinit();
359
360         if(!waserror()){
361                 snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
362                 ksetenv("terminal", buf, 0);
363                 ksetenv("cputype", "arm", 0);
364                 if(cpuserver)
365                         ksetenv("service", "cpu", 0);
366                 else
367                         ksetenv("service", "terminal", 0);
368
369                 /* convert plan9.ini variables to #e and #ec */
370                 for(i = 0; i < nconf; i++) {
371                         ksetenv(confname[i], confval[i], 0);
372                         ksetenv(confname[i], confval[i], 1);
373                 }
374                 poperror();
375         }
376         kproc("alarm", alarmkproc, 0);
377
378         sp = (char**)(USTKTOP - sizeof(Tos) - 8 - sizeof(sp[0])*4);
379         sp[3] = sp[2] = sp[1] = nil;
380         strcpy(sp[0] = (char*)&sp[4], "boot");
381         touser((uintptr)sp);
382 }
383
384 Conf conf;                      /* XXX - must go - gag */
385
386 Confmem sheevamem[] = {
387         /*
388          * Memory available to Plan 9:
389          * the 8K is reserved for ethernet dma access violations to scribble on.
390          */
391         { .base = 0, .limit = 512*MB - 8*1024, },
392 };
393
394 void
395 confinit(void)
396 {
397         int i;
398         ulong kpages;
399         uintptr pa;
400
401         /*
402          * Copy the physical memory configuration to Conf.mem.
403          */
404         if(nelem(sheevamem) > nelem(conf.mem)){
405                 iprint("memory configuration botch\n");
406                 exit(1);
407         }
408         memmove(conf.mem, sheevamem, sizeof(sheevamem));
409
410         conf.npage = 0;
411         pa = PADDR(PGROUND((uintptr)end));
412
413         /*
414          *  we assume that the kernel is at the beginning of one of the
415          *  contiguous chunks of memory and fits therein.
416          */
417         for(i=0; i<nelem(conf.mem); i++){
418                 /* take kernel out of allocatable space */
419                 if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
420                         conf.mem[i].base = pa;
421
422                 conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
423                 conf.npage += conf.mem[i].npage;
424         }
425
426         conf.upages = (conf.npage*90)/100;
427         conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
428
429         /* only one processor */
430         conf.nmach = 1;
431
432         /* set up other configuration parameters */
433         conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
434         if(cpuserver)
435                 conf.nproc *= 3;
436         if(conf.nproc > 2000)
437                 conf.nproc = 2000;
438         conf.nswap = conf.npage*3;
439         conf.nswppo = 4096;
440         conf.nimage = 200;
441
442         conf.copymode = 0;              /* copy on write */
443
444         /*
445          * Guess how much is taken by the large permanent
446          * datastructures. Mntcache and Mntrpc are not accounted for.
447          */
448         kpages = conf.npage - conf.upages;
449         kpages *= BY2PG;
450         kpages -= conf.upages*sizeof(Page)
451                 + conf.nproc*sizeof(Proc)
452                 + conf.nimage*sizeof(Image)
453                 + conf.nswap
454                 + conf.nswppo*sizeof(Page*);
455         mainmem->maxsize = kpages;
456         if(!cpuserver)
457                 /*
458                  * give terminals lots of image memory, too; the dynamic
459                  * allocation will balance the load properly, hopefully.
460                  * be careful with 32-bit overflow.
461                  */
462                 imagmem->maxsize = kpages;
463 }
464
465 int
466 cmpswap(long *addr, long old, long new)
467 {
468         return cas32(addr, old, new);
469 }
470
471 void
472 setupwatchpts(Proc *, Watchpt *, int n)
473 {
474         if(n > 0)
475                 error("no watchpoints");
476 }