]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/teg2/main.c
vmx(1): build vmxgdb by default, clean it up as well
[plan9front.git] / sys / src / 9 / teg2 / 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 #include "io.h"
8 #include "../port/pci.h"
9
10 #include <pool.h>
11
12 #include "arm.h"
13 #include "rebootcode.i"
14
15 /*
16  * Where configuration info is left for the loaded programme.
17  * This will turn into a structure as more is done by the boot loader
18  * (e.g. why parse the .ini file twice?).
19  * There are 3584 bytes available at CONFADDR.
20  */
21 #define BOOTARGS        ((char*)CONFADDR)
22 #define BOOTARGSLEN     (16*KiB)                /* limit in devenv.c */
23 #define MAXCONF         64
24 #define MAXCONFLINE     160
25
26 enum {
27         Minmem  = 256*MB,                       /* conservative default */
28 };
29
30 #define isascii(c) ((uchar)(c) > 0 && (uchar)(c) < 0177)
31
32 extern char bdata[], edata[], end[], etext[];
33
34 uintptr kseg0 = KZERO;
35 Mach* machaddr[MAXMACH];
36 uchar *l2pages;
37
38 Memcache cachel[8];             /* arm arch v7 supports 1-7 */
39 /*
40  * these are used by the cache.v7.s routines.
41  */
42 Lowmemcache *cacheconf;
43
44 int vflag;
45 int normalprint;
46 char debug[256];
47
48 static Lock testlock;
49
50 /* store plan9.ini contents here at least until we stash them in #ec */
51 static char confname[MAXCONF][KNAMELEN];
52 static char confval[MAXCONF][MAXCONFLINE];
53 static int nconf;
54
55 static int
56 findconf(char *name)
57 {
58         int i;
59
60         for(i = 0; i < nconf; i++)
61                 if(cistrcmp(confname[i], name) == 0)
62                         return i;
63         return -1;
64 }
65
66 char*
67 getconf(char *name)
68 {
69         int i;
70
71         i = findconf(name);
72         if(i >= 0)
73                 return confval[i];
74         return nil;
75 }
76
77 void
78 addconf(char *name, char *val)
79 {
80         int i;
81
82         i = findconf(name);
83         if(i < 0){
84                 if(val == nil || nconf >= MAXCONF)
85                         return;
86                 i = nconf++;
87                 strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
88         }
89 //      confval[i] = val;
90         strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
91 }
92
93 static void
94 writeconf(void)
95 {
96         char *p, *q;
97         int n;
98
99         p = getconfenv();
100
101         if(waserror()) {
102                 free(p);
103                 nexterror();
104         }
105
106         /* convert to name=value\n format */
107         for(q=p; *q; q++) {
108                 q += strlen(q);
109                 *q = '=';
110                 q += strlen(q);
111                 *q = '\n';
112         }
113         n = q - p + 1;
114         if(n >= BOOTARGSLEN)
115                 error("kernel configuration too large");
116         memmove(BOOTARGS, p, n);
117         memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
118         poperror();
119         free(p);
120 }
121
122 /*
123  * assumes that we have loaded our /cfg/pxe/mac file at CONFADDR
124  * (usually 0x1000) with tftp in u-boot.  no longer uses malloc, so
125  * can be called early.
126  */
127 static void
128 plan9iniinit(void)
129 {
130         char *k, *v, *next;
131
132         k = (char *)CONFADDR;
133         if(!isascii(*k))
134                 return;
135
136         for(; k && *k != '\0'; k = next) {
137                 if (!isascii(*k))               /* sanity check */
138                         break;
139                 next = strchr(k, '\n');
140                 if (next)
141                         *next++ = '\0';
142
143                 if (*k == '\0' || *k == '\n' || *k == '#')
144                         continue;
145                 v = strchr(k, '=');
146                 if(v == nil)
147                         continue;               /* mal-formed line */
148                 *v++ = '\0';
149
150                 addconf(k, v);
151         }
152 }
153
154 /* enable scheduling of this cpu */
155 void
156 machon(uint cpu)
157 {
158         lock(&active);
159         if (active.machs[cpu] == 0) {   /* currently off? */
160                 active.machs[cpu] = 1;
161                 conf.nmach++;
162         }
163         unlock(&active);
164 }
165
166 /* disable scheduling of this cpu */
167 void
168 machoff(uint cpu)
169 {
170         lock(&active);
171         if (active.machs[cpu]) {                /* currently on? */
172                 active.machs[cpu] = 0;
173                 conf.nmach--;
174         }
175         unlock(&active);
176 }
177
178 void
179 machinit(void)
180 {
181         Mach *m0;
182
183         if (m == 0) {
184                 serialputc('?');
185                 serialputc('m');
186                 serialputc('0');
187         }
188         if(machaddr[m->machno] != m) {
189                 serialputc('?');
190                 serialputc('m');
191                 serialputc('m');
192         }
193
194         if (canlock(&testlock)) {
195                 serialputc('?');
196                 serialputc('l');
197                 panic("cpu%d: locks don't work", m->machno);
198         }
199
200         m->ticks = 1;
201         m->perf.period = 1;
202         m0 = MACHP(0);
203         if (m->machno != 0) {
204                 /* synchronise with cpu 0 */
205                 m->ticks = m0->ticks;
206                 m->fastclock = m0->fastclock;
207                 m->cpuhz = m0->cpuhz;
208                 m->delayloop = m0->delayloop;
209         }
210         if (m->machno != 0 &&
211             (m->fastclock == 0 || m->cpuhz == 0 || m->delayloop == 0))
212                 panic("buggered cpu 0 Mach");
213
214         machon(m->machno);
215         fpoff();
216 }
217
218 /* l.s has already zeroed Mach, which now contains our stack. */
219 void
220 mach0init(void)
221 {
222         if (m == 0) {
223                 serialputc('?');
224                 serialputc('m');
225         }
226         conf.nmach = 0;
227
228         m->machno = 0;
229         machaddr[0] = m;
230
231         lock(&testlock);                /* hold this forever */
232         machinit();
233
234         active.exiting = 0;
235         l1cache->wbse(&active, sizeof active);
236         up = nil;
237 }
238
239 /*
240  *  count CPU's, set up their mach structures and l1 ptes.
241  *  we're running on cpu 0 and our data structures were
242  *  statically allocated.
243  */
244 void
245 launchinit(void)
246 {
247         int mach;
248         Mach *mm;
249         PTE *l1;
250
251         for(mach = 1; mach < MAXMACH; mach++){
252                 machaddr[mach] = mm = mallocalign(MACHSIZE, MACHSIZE, 0, 0);
253                 l1 = mallocalign(L1SIZE, L1SIZE, 0, 0);
254                 if(mm == nil || l1 == nil)
255                         panic("launchinit");
256                 memset(mm, 0, MACHSIZE);
257                 mm->machno = mach;
258
259                 memmove(l1, (void *)L1, L1SIZE);  /* clone cpu0's l1 table */
260                 l1cache->wbse(l1, L1SIZE);
261
262                 mm->mmul1 = l1;
263                 l1cache->wbse(mm, MACHSIZE);
264         }
265         l1cache->wbse(machaddr, sizeof machaddr);
266         conf.nmach = 1;
267 }
268
269 void
270 dump(void *vaddr, int words)
271 {
272         ulong *addr;
273
274         addr = vaddr;
275         while (words-- > 0)
276                 iprint("%.8lux%c", *addr++, words % 8 == 0? '\n': ' ');
277 }
278
279 static void
280 cacheinit(void)
281 {
282         allcacheinfo(cachel);
283         cacheconf = (Lowmemcache *)CACHECONF;
284         cacheconf->l1waysh = cachel[1].waysh;
285         cacheconf->l1setsh = cachel[1].setsh;
286         /* on the tegra 2, l2 is unarchitected */
287         cacheconf->l2waysh = cachel[2].waysh;
288         cacheconf->l2setsh = cachel[2].setsh;
289
290         l2pl310init();
291         allcacheson();
292         allcache->wb();
293 }
294
295 void
296 l2pageinit(void)
297 {
298         l2pages = KADDR(PHYSDRAM + DRAMSIZE - RESRVDHIMEM);
299 }
300
301 /*
302  * at entry, l.s has set m for cpu0 and printed "Plan 9 from Be"
303  * but has not zeroed bss.
304  */
305 void
306 main(void)
307 {
308         int cpu;
309         static ulong vfy = 0xcafebabe;
310
311         up = nil;
312         if (vfy != 0xcafebabe) {
313                 serialputc('?');
314                 serialputc('d');
315                 panic("data segment misaligned");
316         }
317
318         memset(edata, 0, end - edata);
319
320         /*
321          * we can't lock until smpon has run, but we're supposed to wait
322          * until l1 & l2 are on.  too bad.  l1 is on, l2 will soon be.
323          */
324         smpon();
325         iprint("ll Labs ");
326         cacheinit();
327
328         /*
329          * data segment is aligned, bss is zeroed, caches' characteristics
330          * are known.  begin initialisation.
331          */
332         mach0init();
333         l2pageinit();
334         mmuinit();
335
336         quotefmtinstall();
337
338         /* want plan9.ini to be able to affect memory sizing in confinit */
339         plan9iniinit();         /* before we step on plan9.ini in low memory */
340
341         /* l2 looks for *l2off= in plan9.ini */
342         l2cache->on();          /* l2->on requires locks to work, thus smpon */
343         l2cache->info(&cachel[2]);
344         allcache->on();
345
346         cortexa9cachecfg();
347
348         trapinit();             /* so confinit can probe memory to size it */
349         confinit();             /* figures out amount of memory */
350         /* xinit prints (if it can), so finish up the banner here. */
351         delay(100);
352         navailcpus = getncpus();
353         iprint("(mp arm; %d cpus)\n\n", navailcpus);
354         delay(100);
355
356         for (cpu = 1; cpu < navailcpus; cpu++)
357                 stopcpu(cpu);
358
359         xinit();
360         irqtooearly = 0;        /* now that xinit and trapinit have run */
361
362         mainmem->flags |= POOL_ANTAGONISM /* | POOL_PARANOIA */ ;
363
364         /*
365          * Printinit will cause the first malloc call.
366          * (printinit->qopen->malloc) unless any of the
367          * above (like clockinit) do an irqenable, which
368          * will call malloc.
369          * If the system dies here it's probably due
370          * to malloc(->xalloc) not being initialised
371          * correctly, or the data segment is misaligned
372          * (it's amazing how far you can get with
373          * things like that completely broken).
374          *
375          * (Should be) boilerplate from here on.
376          */
377
378         archreset();                    /* cfg clock signals, print cache cfg */
379         clockinit();                    /* start clocks */
380         timersinit();
381
382         delay(50);                      /* let uart catch up */
383         printinit();
384
385         cpuidprint();
386         chkmissing();
387
388         procinit0();
389         initseg();
390
391 //      dmainit();
392         links();
393         conf.monitor = 1;
394 //      screeninit();
395
396         iprint("pcireset...");
397         pcireset();                     /* this tends to hang after a reboot */
398         iprint("ok\n");
399
400         chandevreset();                 /* most devices are discovered here */
401 //      i8250console();                 /* too early; see init0 */
402
403         pageinit();                     /* prints "1020M memory: â‹¯ */
404         userinit();
405
406         /*
407          * starting a cpu will eventually result in it calling schedinit,
408          * so everything necessary to run user processes should be set up
409          * before starting secondary cpus.
410          */
411         launchinit();
412         /* SMP & FW are already on when we get here; u-boot set them? */
413         for (cpu = 1; cpu < navailcpus; cpu++)
414                 if (startcpu(cpu) < 0)
415                         panic("cpu%d didn't start", cpu);
416         l1diag();
417
418         schedinit();
419         panic("cpu%d: schedinit returned", m->machno);
420 }
421
422 /*
423  *  exit kernel either on a panic or user request
424  */
425 void
426 exit(int)
427 {
428         cpushutdown();
429         splhi();
430         if (m->machno == 0)
431                 archreboot();
432         else {
433                 intrcpushutdown();
434                 stopcpu(m->machno);
435                 for (;;)
436                         idlehands();
437         }
438 }
439
440 int
441 isaconfig(char *class, int ctlrno, ISAConf *isa)
442 {
443         char cc[32], *p, *x;
444         int i;
445
446         snprint(cc, sizeof cc, "%s%d", class, ctlrno);
447         p = getconf(cc);
448         if(p == nil)
449                 return 0;
450
451         x = nil;
452         kstrdup(&x, p);
453         p = x;
454
455         isa->type = "";
456         isa->nopt = tokenize(p, isa->opt, NISAOPT);
457         for(i = 0; i < isa->nopt; i++){
458                 p = isa->opt[i];
459                 if(cistrncmp(p, "type=", 5) == 0)
460                         isa->type = p + 5;
461                 else if(cistrncmp(p, "port=", 5) == 0)
462                         isa->port = strtoul(p+5, &p, 0);
463                 else if(cistrncmp(p, "irq=", 4) == 0)
464                         isa->irq = strtoul(p+4, &p, 0);
465                 else if(cistrncmp(p, "dma=", 4) == 0)
466                         isa->dma = strtoul(p+4, &p, 0);
467                 else if(cistrncmp(p, "mem=", 4) == 0)
468                         isa->mem = strtoul(p+4, &p, 0);
469                 else if(cistrncmp(p, "size=", 5) == 0)
470                         isa->size = strtoul(p+5, &p, 0);
471                 else if(cistrncmp(p, "freq=", 5) == 0)
472                         isa->freq = strtoul(p+5, &p, 0);
473         }
474         return 1;
475 }
476
477 /*
478  * the new kernel is already loaded at address `code'
479  * of size `size' and entry point `entry'.
480  */
481 void
482 reboot(void *entry, void *code, ulong size)
483 {
484         void (*f)(ulong, ulong, ulong);
485
486         writeconf();
487
488         /*
489          * the boot processor is cpu0.  execute this function on it
490          * so that the new kernel has the same cpu0.
491          */
492         if (m->machno != 0) {
493                 procwired(up, 0);
494                 sched();
495         }
496         cpushutdown();
497
498         /*
499          * should be the only processor running now
500          */
501         pcireset();
502
503         /* turn off buffered serial console */
504         serialoq = nil;
505         kprintoq = nil;
506         screenputs = nil;
507
508         /* shutdown devices */
509         chandevshutdown();
510
511         /* call off the dog */
512         clockshutdown();
513
514         splhi();
515         intrshutdown();
516
517         /* setup reboot trampoline function */
518         f = (void*)REBOOTADDR;
519         memmove(f, rebootcode, sizeof(rebootcode));
520         cachedwb();
521         l2cache->wbinv();
522         l2cache->off();
523         cacheuwbinv();
524
525         /* off we go - never to return */
526         (*f)(PADDR(entry), PADDR(code), size);
527 }
528
529 /*
530  *  starting place for first process
531  */
532 void
533 init0(void)
534 {
535         char buf[2*KNAMELEN], **sp;
536         int i;
537
538         chandevinit();
539         i8250console();         /* might be redundant, but harmless */
540         if(serialoq == nil)
541                 panic("init0: nil serialoq");
542         normalprint = 1;
543
544         if(!waserror()){
545                 snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
546                 ksetenv("terminal", buf, 0);
547                 ksetenv("cputype", "arm", 0);
548                 if(cpuserver)
549                         ksetenv("service", "cpu", 0);
550                 else
551                         ksetenv("service", "terminal", 0);
552
553                 /* convert plan9.ini variables to #e and #ec */
554                 for(i = 0; i < nconf; i++) {
555                         ksetenv(confname[i], confval[i], 0);
556                         ksetenv(confname[i], confval[i], 1);
557                 }
558                 poperror();
559         }
560         kproc("alarm", alarmkproc, 0);
561
562         sp = (char**)(USTKTOP - sizeof(Tos) - 8 - sizeof(sp[0])*4);
563         sp[3] = sp[2] = sp[1] = nil;
564         strcpy(sp[0] = (char*)&sp[4], "boot");
565         touser((uintptr)sp);
566 }
567
568 Conf conf;                      /* XXX - must go - gag */
569
570 Confmem tsmem[nelem(conf.mem)] = {
571         /*
572          * Memory available to Plan 9:
573          */
574         { .base = PHYSDRAM, .limit = PHYSDRAM + Minmem, },
575 };
576 ulong memsize = DRAMSIZE;
577
578 static int
579 gotmem(uintptr sz)
580 {
581         uintptr addr;
582
583         /* back off a little from the end */
584         addr = (uintptr)KADDR(PHYSDRAM + sz - BY2WD);
585         if (probeaddr(addr) >= 0) {     /* didn't trap? memory present */
586                 memsize = sz;
587                 return 0;
588         }
589         return -1;
590 }
591
592 void
593 confinit(void)
594 {
595         int i;
596         ulong kpages;
597         uintptr pa;
598         char *p;
599
600         if(p = getconf("service")){
601                 if(strcmp(p, "cpu") == 0)
602                         cpuserver = 1;
603                 else if(strcmp(p,"terminal") == 0)
604                         cpuserver = 0;
605         }
606
607         /*
608          * Copy the physical memory configuration to Conf.mem.
609          */
610         if(nelem(tsmem) > nelem(conf.mem)){
611                 iprint("memory configuration botch\n");
612                 exit(1);
613         }
614         if(0 && (p = getconf("*maxmem")) != nil) {
615                 memsize = strtoul(p, 0, 0) - PHYSDRAM;
616                 if (memsize < 16*MB)            /* sanity */
617                         memsize = 16*MB;
618         }
619
620         /*
621          * see if all that memory exists; if not, find out how much does.
622          * trapinit must have been called first.
623          */
624         if (gotmem(memsize - RESRVDHIMEM) < 0)
625                 panic("can't find 1GB of memory");
626
627         tsmem[0].limit = PHYSDRAM + memsize;
628         memmove(conf.mem, tsmem, sizeof(tsmem));
629
630         conf.npage = 0;
631         pa = PADDR(PGROUND((uintptr)end));
632
633         /*
634          *  we assume that the kernel is at the beginning of one of the
635          *  contiguous chunks of memory and fits therein.
636          */
637         for(i=0; i<nelem(conf.mem); i++){
638                 /* take kernel out of allocatable space */
639                 if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
640                         conf.mem[i].base = pa;
641
642                 conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
643                 conf.npage += conf.mem[i].npage;
644         }
645
646         conf.upages = (conf.npage*80)/100;
647         conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
648
649         /* set up other configuration parameters */
650         conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
651         if(cpuserver)
652                 conf.nproc *= 3;
653         if(conf.nproc > 2000)
654                 conf.nproc = 2000;
655         conf.nswap = conf.npage*3;
656         conf.nswppo = 4096;
657         conf.nimage = 200;
658
659         /*
660          * it's simpler on mp systems to take page-faults early,
661          * on reference, rather than later, on write, which might
662          * require tlb shootdowns.
663          */
664         conf.copymode = 1;              /* copy on reference */
665
666         /*
667          * Guess how much is taken by the large permanent
668          * datastructures. Mntcache and Mntrpc are not accounted for.
669          */
670         kpages = conf.npage - conf.upages;
671         kpages *= BY2PG;
672         kpages -= conf.upages*sizeof(Page)
673                 + conf.nproc*sizeof(Proc)
674                 + conf.nimage*sizeof(Image)
675                 + conf.nswap
676                 + conf.nswppo*sizeof(Page*);
677         mainmem->maxsize = kpages;
678         if(!cpuserver)
679                 /*
680                  * give terminals lots of image memory, too; the dynamic
681                  * allocation will balance the load properly, hopefully.
682                  * be careful with 32-bit overflow.
683                  */
684                 imagmem->maxsize = kpages;
685 }
686
687 void
688 advertwfi(void)                 /* advertise my wfi status */
689 {
690         ilock(&active);
691         active.wfi |= 1 << m->machno;
692         iunlock(&active);
693 }
694
695 void
696 unadvertwfi(void)               /* do not advertise my wfi status */
697 {
698         ilock(&active);
699         active.wfi &= ~(1 << m->machno);
700         iunlock(&active);
701 }
702
703 void
704 idlehands(void)
705 {
706 #ifdef use_ipi
707         int advertised;
708
709         /* don't go into wfi until my local timer is ticking */
710         if (m->ticks <= 1)
711                 return;
712
713         advertised = 0;
714         m->inidlehands++;
715         /* avoid recursion via ilock, advertise iff this cpu is initialised */
716         if (m->inidlehands == 1 && m->syscall > 0) {
717                 advertwfi();
718                 advertised = 1;
719         }
720
721         wfi();
722
723         if (advertised)
724                 unadvertwfi();
725         m->inidlehands--;
726 #endif
727 }
728
729 void
730 wakewfi(void)
731 {
732 #ifdef use_ipi
733         uint cpu;
734
735         /*
736          * find any cpu other than me currently in wfi.
737          * need not be exact.
738          */
739         cpu = BI2BY*BY2WD - 1 - clz(active.wfi & ~(1 << m->machno));
740         if (cpu < MAXMACH)
741                 intrcpu(cpu);
742 #endif
743 }
744
745 void
746 setupwatchpts(Proc *, Watchpt *, int n)
747 {
748         if(n > 0)
749                 error("no watchpoints");
750 }