]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/omap/main.c
kernel: fix wrong calculation of swap iolist size
[plan9front.git] / sys / src / 9 / omap / main.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7
8 #include "init.h"
9 #include <pool.h>
10
11 #include "reboot.h"
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 enum {
25         Minmem  = 256*MB,                       /* conservative default */
26 };
27
28 #define isascii(c) ((uchar)(c) > 0 && (uchar)(c) < 0177)
29
30 uintptr kseg0 = KZERO;
31 Mach* machaddr[MAXMACH];
32
33 /*
34  * Option arguments from the command line.
35  * oargv[0] is the boot file.
36  * Optionsinit() is called from multiboot()
37  * or some other machine-dependent place
38  * to set it all up.
39  */
40 static int oargc;
41 static char* oargv[20];
42 static char oargb[128];
43 static int oargblen;
44 static char oenv[4096];
45
46 static uintptr sp;              /* XXX - must go - user stack of init proc */
47
48 int vflag;
49 int normalprint;
50 char debug[256];
51
52 /* store plan9.ini contents here at least until we stash them in #ec */
53 static char confname[MAXCONF][KNAMELEN];
54 static char confval[MAXCONF][MAXCONFLINE];
55 static int nconf;
56
57 static int
58 findconf(char *name)
59 {
60         int i;
61
62         for(i = 0; i < nconf; i++)
63                 if(cistrcmp(confname[i], name) == 0)
64                         return i;
65         return -1;
66 }
67
68 char*
69 getconf(char *name)
70 {
71         int i;
72
73         i = findconf(name);
74         if(i >= 0)
75                 return confval[i];
76         return nil;
77 }
78
79 void
80 addconf(char *name, char *val)
81 {
82         int i;
83
84         i = findconf(name);
85         if(i < 0){
86                 if(val == nil || nconf >= MAXCONF)
87                         return;
88                 i = nconf++;
89                 strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
90         }
91 //      confval[i] = val;
92         strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
93 }
94
95 static void
96 writeconf(void)
97 {
98         char *p, *q;
99         int n;
100
101         p = getconfenv();
102
103         if(waserror()) {
104                 free(p);
105                 nexterror();
106         }
107
108         /* convert to name=value\n format */
109         for(q=p; *q; q++) {
110                 q += strlen(q);
111                 *q = '=';
112                 q += strlen(q);
113                 *q = '\n';
114         }
115         n = q - p + 1;
116         if(n >= BOOTARGSLEN)
117                 error("kernel configuration too large");
118         memmove(BOOTARGS, p, n);
119         memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
120         poperror();
121         free(p);
122 }
123
124 /*
125  * assumes that we have loaded our /cfg/pxe/mac file at 0x1000 with
126  * tftp in u-boot.  no longer uses malloc, so can be called early.
127  */
128 static void
129 plan9iniinit(void)
130 {
131         char *k, *v, *next;
132
133         k = (char *)CONFADDR;
134         if(!isascii(*k))
135                 return;
136
137         for(; k && *k != '\0'; k = next) {
138                 if (!isascii(*k))               /* sanity check */
139                         break;
140                 next = strchr(k, '\n');
141                 if (next)
142                         *next++ = '\0';
143
144                 if (*k == '\0' || *k == '\n' || *k == '#')
145                         continue;
146                 v = strchr(k, '=');
147                 if(v == nil)
148                         continue;               /* mal-formed line */
149                 *v++ = '\0';
150
151                 addconf(k, v);
152         }
153 }
154
155 static void
156 optionsinit(char* s)
157 {
158         char *o;
159
160         strcpy(oenv, "");
161         o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
162         if(getenv("bootargs", o, o - oargb) != nil)
163                 *(o-1) = ' ';
164
165         oargblen = strlen(oargb);
166         oargc = tokenize(oargb, oargv, nelem(oargv)-1);
167         oargv[oargc] = nil;
168 }
169
170 char*
171 getenv(char* name, char* buf, int n)
172 {
173         char *e, *p, *q;
174
175         p = oenv;
176         while(*p != 0){
177                 if((e = strchr(p, '=')) == nil)
178                         break;
179                 for(q = name; p < e; p++){
180                         if(*p != *q)
181                                 break;
182                         q++;
183                 }
184                 if(p == e && *q == 0){
185                         strecpy(buf, buf+n, e+1);
186                         return buf;
187                 }
188                 p += strlen(p)+1;
189         }
190
191         return nil;
192 }
193
194 void
195 main(void)
196 {
197 //      int i;
198         extern char bdata[], edata[], end[], etext[];
199         static ulong vfy = 0xcafebabe;
200
201         /* l.s has already printed "Plan 9 from Be" */
202 //      m = mach;                                       /* now done in l.s */
203
204         /* realign data seg; apparently -H0 -R4096 does not pad the text seg */
205         if (vfy != 0xcafebabe) {
206 //              wave('<'); wave('-');
207                 memmove(bdata, etext, edata - bdata);
208         }
209         /*
210          * once data segment is in place, always zero bss since we may
211          * have been loaded by another Plan 9 kernel.
212          */
213         memset(edata, 0, end - edata);          /* zero BSS */
214         cacheuwbinv();
215         l2cacheuwbinv();
216
217         if (vfy != 0xcafebabe)
218                 panic("data segment misaligned");
219         vfy = 0;
220
221 wave('l');
222         machinit();
223         mmuinit();
224
225         optionsinit("/boot/boot boot");
226         quotefmtinstall();
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         trapinit();             /* so confinit can probe memory to size it */
232         confinit();             /* figures out amount of memory */
233         /* xinit prints (if it can), so finish up the banner here. */
234         delay(500);
235         iprint("l Labs\n\n");
236         delay(500);
237         xinit();
238
239         mainmem->flags |= POOL_ANTAGONISM /* | POOL_PARANOIA */ ;
240
241         /*
242          * Printinit will cause the first malloc call.
243          * (printinit->qopen->malloc) unless any of the
244          * above (like clockinit) do an irqenable, which
245          * will call malloc.
246          * If the system dies here it's probably due
247          * to malloc(->xalloc) not being initialised
248          * correctly, or the data segment is misaligned
249          * (it's amazing how far you can get with
250          * things like that completely broken).
251          *
252          * (Should be) boilerplate from here on.
253          */
254
255         archreset();                    /* configure clock signals */
256         clockinit();                    /* start clocks */
257         timersinit();
258         watchdoginit();
259
260         delay(250);                     /* let uart catch up */
261         printinit();
262 //      kbdenable();
263
264         cpuidprint();
265 //      chkmissing();
266
267         procinit0();
268         initseg();
269
270         dmainit();
271         links();
272         conf.monitor = 1;
273         screeninit();
274         chandevreset();                 /* most devices are discovered here */
275
276 //      i8250console();                 /* too early; see init0 */
277
278         pageinit();
279         swapinit();
280         userinit();
281         schedinit();
282 }
283
284 void
285 machinit(void)
286 {
287         if (m == 0)
288                 wave('?');
289 //      memset(m, 0, sizeof(Mach));     /* done by l.s, now contains stack */
290         m->machno = 0;
291         machaddr[m->machno] = m;
292
293         m->ticks = 1;
294         m->perf.period = 1;
295
296         conf.nmach = 1;
297
298         active.machs = 1;
299         active.exiting = 0;
300
301         up = nil;
302 }
303
304 static void
305 shutdown(int ispanic)
306 {
307         int ms, once;
308
309         lock(&active);
310         if(ispanic)
311                 active.ispanic = ispanic;
312         else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
313                 active.ispanic = 0;
314         once = active.machs & (1<<m->machno);
315         active.machs &= ~(1<<m->machno);
316         active.exiting = 1;
317         unlock(&active);
318
319         if(once)
320                 iprint("cpu%d: exiting\n", m->machno);
321         spllo();
322         for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
323                 delay(TK2MS(2));
324                 if(active.machs == 0 && consactive() == 0)
325                         break;
326         }
327         delay(1000);
328 }
329
330 /*
331  *  exit kernel either on a panic or user request
332  */
333 void
334 exit(int code)
335 {
336         shutdown(code);
337         splhi();
338         archreboot();
339 }
340
341 int
342 isaconfig(char *class, int ctlrno, ISAConf *isa)
343 {
344         char cc[32], *p;
345         int i;
346
347         snprint(cc, sizeof cc, "%s%d", class, ctlrno);
348         p = getconf(cc);
349         if(p == nil)
350                 return 0;
351
352         isa->type = "";
353         isa->nopt = tokenize(p, isa->opt, NISAOPT);
354         for(i = 0; i < isa->nopt; i++){
355                 p = isa->opt[i];
356                 if(cistrncmp(p, "type=", 5) == 0)
357                         isa->type = p + 5;
358                 else if(cistrncmp(p, "port=", 5) == 0)
359                         isa->port = strtoul(p+5, &p, 0);
360                 else if(cistrncmp(p, "irq=", 4) == 0)
361                         isa->irq = strtoul(p+4, &p, 0);
362                 else if(cistrncmp(p, "dma=", 4) == 0)
363                         isa->dma = strtoul(p+4, &p, 0);
364                 else if(cistrncmp(p, "mem=", 4) == 0)
365                         isa->mem = strtoul(p+4, &p, 0);
366                 else if(cistrncmp(p, "size=", 5) == 0)
367                         isa->size = strtoul(p+5, &p, 0);
368                 else if(cistrncmp(p, "freq=", 5) == 0)
369                         isa->freq = strtoul(p+5, &p, 0);
370         }
371         return 1;
372 }
373
374 /*
375  * the new kernel is already loaded at address `code'
376  * of size `size' and entry point `entry'.
377  */
378 void
379 reboot(void *entry, void *code, ulong size)
380 {
381         void (*f)(ulong, ulong, ulong);
382
383         print("starting reboot...");
384         writeconf();
385         shutdown(0);
386
387         /*
388          * should be the only processor running now
389          */
390
391         print("reboot entry %#lux code %#lux size %ld\n",
392                 PADDR(entry), PADDR(code), size);
393         delay(100);
394
395         /* turn off buffered serial console */
396         serialoq = nil;
397         kprintoq = nil;
398         screenputs = nil;
399
400         /* shutdown devices */
401         chandevshutdown();
402
403         /* call off the dog */
404         clockshutdown();
405
406         splhi();
407         intrsoff();
408
409         /* setup reboot trampoline function */
410         f = (void*)REBOOTADDR;
411         memmove(f, rebootcode, sizeof(rebootcode));
412         cacheuwbinv();
413         l2cacheuwbinv();
414
415         /* off we go - never to return */
416         (*f)(PADDR(entry), PADDR(code), size);
417
418         iprint("loaded kernel returned!\n");
419         delay(1000);
420         archreboot();
421 }
422
423 /*
424  *  starting place for first process
425  */
426 void
427 init0(void)
428 {
429         int i;
430         char buf[2*KNAMELEN];
431
432         up->nerrlab = 0;
433         coherence();
434         spllo();
435
436         /*
437          * These are o.k. because rootinit is null.
438          * Then early kproc's will have a root and dot.
439          */
440         up->slash = namec("#/", Atodir, 0, 0);
441         pathclose(up->slash->path);
442         up->slash->path = newpath("/");
443         up->dot = cclone(up->slash);
444
445         dmatest();              /* needs `up' set, so can't do it earlier */
446         chandevinit();
447         i8250console();         /* might be redundant, but harmless */
448         if(serialoq == nil)
449                 panic("init0: nil serialoq");
450         normalprint = 1;
451
452         if(!waserror()){
453                 snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
454                 ksetenv("terminal", buf, 0);
455                 ksetenv("cputype", "arm", 0);
456                 if(cpuserver)
457                         ksetenv("service", "cpu", 0);
458                 else
459                         ksetenv("service", "terminal", 0);
460
461                 /* convert plan9.ini variables to #e and #ec */
462                 for(i = 0; i < nconf; i++) {
463                         ksetenv(confname[i], confval[i], 0);
464                         ksetenv(confname[i], confval[i], 1);
465                 }
466                 poperror();
467         }
468         kproc("alarm", alarmkproc, 0);
469         touser(sp);
470 }
471
472 static void
473 bootargs(uintptr base)
474 {
475         int i;
476         ulong ssize;
477         char **av, *p;
478
479         /*
480          * Push the boot args onto the stack.
481          * The initial value of the user stack must be such
482          * that the total used is larger than the maximum size
483          * of the argument list checked in syscall.
484          */
485         i = oargblen+1;
486         p = UINT2PTR(STACKALIGN(base + BY2PG - sizeof(up->s.args) - i));
487         memmove(p, oargb, i);
488
489         /*
490          * Now push argc and the argv pointers.
491          * This isn't strictly correct as the code jumped to by
492          * touser in init9.s calls startboot (port/initcode.c) which
493          * expects arguments
494          *      startboot(char *argv0, char **argv)
495          * not the usual (int argc, char* argv[]), but argv0 is
496          * unused so it doesn't matter (at the moment...).
497          */
498         av = (char**)(p - (oargc+2)*sizeof(char*));
499         ssize = base + BY2PG - PTR2UINT(av);
500         *av++ = (char*)oargc;
501         for(i = 0; i < oargc; i++)
502                 *av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
503         *av = nil;
504
505         /*
506          * Leave space for the return PC of the
507          * caller of initcode.
508          */
509         sp = USTKTOP - ssize - sizeof(void*);
510 }
511
512 /*
513  *  create the first process
514  */
515 void
516 userinit(void)
517 {
518         Proc *p;
519         Segment *s;
520         KMap *k;
521         Page *pg;
522
523         /* no processes yet */
524         up = nil;
525
526         p = newproc();
527         p->pgrp = newpgrp();
528         p->egrp = smalloc(sizeof(Egrp));
529         p->egrp->ref = 1;
530         p->fgrp = dupfgrp(nil);
531         p->rgrp = newrgrp();
532         p->procmode = 0640;
533
534         kstrdup(&eve, "");
535         kstrdup(&p->text, "*init*");
536         kstrdup(&p->user, eve);
537
538         /*
539          * Kernel Stack
540          */
541         p->sched.pc = PTR2UINT(init0);
542         p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
543         p->sched.sp = STACKALIGN(p->sched.sp);
544
545         /*
546          * User Stack
547          *
548          * Technically, newpage can't be called here because it
549          * should only be called when in a user context as it may
550          * try to sleep if there are no pages available, but that
551          * shouldn't be the case here.
552          */
553         s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
554         s->flushme++;
555         p->seg[SSEG] = s;
556         pg = newpage(1, 0, USTKTOP-BY2PG);
557         segpage(s, pg);
558         k = kmap(pg);
559         bootargs(VA(k));
560         kunmap(k);
561
562         /*
563          * Text
564          */
565         s = newseg(SG_TEXT, UTZERO, 1);
566         p->seg[TSEG] = s;
567         pg = newpage(1, 0, UTZERO);
568         memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
569         segpage(s, pg);
570         k = kmap(s->map[0]->pages[0]);
571         memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
572         kunmap(k);
573
574         ready(p);
575 }
576
577 Conf conf;                      /* XXX - must go - gag */
578
579 Confmem omapmem[nelem(conf.mem)] = {
580         /*
581          * Memory available to Plan 9:
582          */
583         { .base = PHYSDRAM, .limit = PHYSDRAM + Minmem, },
584 };
585 ulong memsize = Minmem;
586
587 static int
588 gotmem(uintptr sz)
589 {
590         uintptr addr;
591
592         addr = PHYSDRAM + sz - BY2WD;
593         mmuidmap(addr, 1);
594         if (probeaddr(addr) >= 0) {
595                 memsize = sz;
596                 return 0;
597         }
598         return -1;
599 }
600
601 void
602 confinit(void)
603 {
604         int i;
605         ulong kpages;
606         uintptr pa;
607         char *p;
608
609         /*
610          * Copy the physical memory configuration to Conf.mem.
611          */
612         if(nelem(omapmem) > nelem(conf.mem)){
613                 iprint("memory configuration botch\n");
614                 exit(1);
615         }
616         if((p = getconf("*maxmem")) != nil) {
617                 memsize = strtoul(p, 0, 0) - PHYSDRAM;
618                 if (memsize < 16*MB)            /* sanity */
619                         memsize = 16*MB;
620         }
621
622         /*
623          * see if all that memory exists; if not, find out how much does.
624          * trapinit must have been called first.
625          */
626         if (gotmem(memsize) < 0 && gotmem(256*MB) < 0 && gotmem(128*MB) < 0) {
627                 iprint("can't find any memory, assuming %dMB\n", Minmem / MB);
628                 memsize = Minmem;
629         }
630
631         omapmem[0].limit = PHYSDRAM + memsize;
632         memmove(conf.mem, omapmem, sizeof(omapmem));
633
634         conf.npage = 0;
635         pa = PADDR(PGROUND(PTR2UINT(end)));
636
637         /*
638          *  we assume that the kernel is at the beginning of one of the
639          *  contiguous chunks of memory and fits therein.
640          */
641         for(i=0; i<nelem(conf.mem); i++){
642                 /* take kernel out of allocatable space */
643                 if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
644                         conf.mem[i].base = pa;
645
646                 conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
647                 conf.npage += conf.mem[i].npage;
648         }
649
650         conf.upages = (conf.npage*80)/100;
651         conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
652
653         /* only one processor */
654         conf.nmach = 1;
655
656         /* set up other configuration parameters */
657         conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
658         if(cpuserver)
659                 conf.nproc *= 3;
660         if(conf.nproc > 2000)
661                 conf.nproc = 2000;
662         conf.nswap = conf.npage*3;
663         conf.nswppo = 4096;
664         conf.nimage = 200;
665
666         conf.copymode = 0;              /* copy on write */
667
668         /*
669          * Guess how much is taken by the large permanent
670          * datastructures. Mntcache and Mntrpc are not accounted for
671          * (probably ~300KB).
672          */
673         kpages = conf.npage - conf.upages;
674         kpages *= BY2PG;
675         kpages -= conf.upages*sizeof(Page)
676                 + conf.nproc*sizeof(Proc)
677                 + conf.nimage*sizeof(Image)
678                 + conf.nswap
679                 + conf.nswppo*sizeof(Page*);
680         mainmem->maxsize = kpages;
681         if(!cpuserver)
682                 /*
683                  * give terminals lots of image memory, too; the dynamic
684                  * allocation will balance the load properly, hopefully.
685                  * be careful with 32-bit overflow.
686                  */
687                 imagmem->maxsize = kpages;
688
689 //      archconfinit();
690 }
691
692 int
693 cmpswap(long *addr, long old, long new)
694 {
695         return cas32(addr, old, new);
696 }