]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/omap/main.c
pc, pc64: warn when running out of conf.mem[] entries in meminit()
[plan9front.git] / sys / src / 9 / omap / 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
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 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 int vflag;
34 int normalprint;
35 char debug[256];
36
37 /* store plan9.ini contents here at least until we stash them in #ec */
38 static char confname[MAXCONF][KNAMELEN];
39 static char confval[MAXCONF][MAXCONFLINE];
40 static int nconf;
41
42 static int
43 findconf(char *name)
44 {
45         int i;
46
47         for(i = 0; i < nconf; i++)
48                 if(cistrcmp(confname[i], name) == 0)
49                         return i;
50         return -1;
51 }
52
53 char*
54 getconf(char *name)
55 {
56         int i;
57
58         i = findconf(name);
59         if(i >= 0)
60                 return confval[i];
61         return nil;
62 }
63
64 void
65 addconf(char *name, char *val)
66 {
67         int i;
68
69         i = findconf(name);
70         if(i < 0){
71                 if(val == nil || nconf >= MAXCONF)
72                         return;
73                 i = nconf++;
74                 strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
75         }
76 //      confval[i] = val;
77         strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
78 }
79
80 static void
81 writeconf(void)
82 {
83         char *p, *q;
84         int n;
85
86         p = getconfenv();
87
88         if(waserror()) {
89                 free(p);
90                 nexterror();
91         }
92
93         /* convert to name=value\n format */
94         for(q=p; *q; q++) {
95                 q += strlen(q);
96                 *q = '=';
97                 q += strlen(q);
98                 *q = '\n';
99         }
100         n = q - p + 1;
101         if(n >= BOOTARGSLEN)
102                 error("kernel configuration too large");
103         memmove(BOOTARGS, p, n);
104         memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
105         poperror();
106         free(p);
107 }
108
109 /*
110  * assumes that we have loaded our /cfg/pxe/mac file at 0x1000 with
111  * tftp in u-boot.  no longer uses malloc, so can be called early.
112  */
113 static void
114 plan9iniinit(void)
115 {
116         char *k, *v, *next;
117
118         k = (char *)CONFADDR;
119         if(!isascii(*k))
120                 return;
121
122         for(; k && *k != '\0'; k = next) {
123                 if (!isascii(*k))               /* sanity check */
124                         break;
125                 next = strchr(k, '\n');
126                 if (next)
127                         *next++ = '\0';
128
129                 if (*k == '\0' || *k == '\n' || *k == '#')
130                         continue;
131                 v = strchr(k, '=');
132                 if(v == nil)
133                         continue;               /* mal-formed line */
134                 *v++ = '\0';
135
136                 addconf(k, v);
137         }
138 }
139
140 void
141 main(void)
142 {
143 //      int i;
144         extern char bdata[], edata[], end[], etext[];
145         static ulong vfy = 0xcafebabe;
146
147         /* l.s has already printed "Plan 9 from Be" */
148 //      m = mach;                                       /* now done in l.s */
149
150         /* realign data seg; apparently -H0 -R4096 does not pad the text seg */
151         if (vfy != 0xcafebabe) {
152 //              wave('<'); wave('-');
153                 memmove(bdata, etext, edata - bdata);
154         }
155         /*
156          * once data segment is in place, always zero bss since we may
157          * have been loaded by another Plan 9 kernel.
158          */
159         memset(edata, 0, end - edata);          /* zero BSS */
160         cacheuwbinv();
161         l2cacheuwbinv();
162
163         if (vfy != 0xcafebabe)
164                 panic("data segment misaligned");
165         vfy = 0;
166
167 wave('l');
168         machinit();
169         mmuinit();
170
171         quotefmtinstall();
172
173         /* want plan9.ini to be able to affect memory sizing in confinit */
174         plan9iniinit();         /* before we step on plan9.ini in low memory */
175
176         trapinit();             /* so confinit can probe memory to size it */
177         confinit();             /* figures out amount of memory */
178         /* xinit prints (if it can), so finish up the banner here. */
179         delay(500);
180         iprint("l Labs\n\n");
181         delay(500);
182         xinit();
183
184         mainmem->flags |= POOL_ANTAGONISM /* | POOL_PARANOIA */ ;
185
186         /*
187          * Printinit will cause the first malloc call.
188          * (printinit->qopen->malloc) unless any of the
189          * above (like clockinit) do an irqenable, which
190          * will call malloc.
191          * If the system dies here it's probably due
192          * to malloc(->xalloc) not being initialised
193          * correctly, or the data segment is misaligned
194          * (it's amazing how far you can get with
195          * things like that completely broken).
196          *
197          * (Should be) boilerplate from here on.
198          */
199
200         archreset();                    /* configure clock signals */
201         clockinit();                    /* start clocks */
202         timersinit();
203         watchdoginit();
204
205         delay(250);                     /* let uart catch up */
206         printinit();
207 //      kbdenable();
208
209         cpuidprint();
210 //      chkmissing();
211
212         procinit0();
213         initseg();
214
215         dmainit();
216         links();
217         conf.monitor = 1;
218         screeninit();
219         chandevreset();                 /* most devices are discovered here */
220
221 //      i8250console();                 /* too early; see init0 */
222
223         pageinit();
224         userinit();
225         schedinit();
226 }
227
228 void
229 machinit(void)
230 {
231         if (m == 0)
232                 wave('?');
233 //      memset(m, 0, sizeof(Mach));     /* done by l.s, now contains stack */
234         m->machno = 0;
235         machaddr[m->machno] = m;
236
237         m->ticks = 1;
238         m->perf.period = 1;
239
240         conf.nmach = 1;
241
242         active.machs[0] = 1;
243         active.exiting = 0;
244
245         up = nil;
246 }
247
248 /*
249  *  exit kernel either on a panic or user request
250  */
251 void
252 exit(int)
253 {
254         cpushutdown();
255         splhi();
256         archreboot();
257 }
258
259 int
260 isaconfig(char *class, int ctlrno, ISAConf *isa)
261 {
262         char cc[32], *p, *x;
263         int i;
264
265         snprint(cc, sizeof cc, "%s%d", class, ctlrno);
266         p = getconf(cc);
267         if(p == nil)
268                 return 0;
269
270         x = nil;
271         kstrdup(&x, p);
272         p = x;
273
274         isa->type = "";
275         isa->nopt = tokenize(p, isa->opt, NISAOPT);
276         for(i = 0; i < isa->nopt; i++){
277                 p = isa->opt[i];
278                 if(cistrncmp(p, "type=", 5) == 0)
279                         isa->type = p + 5;
280                 else if(cistrncmp(p, "port=", 5) == 0)
281                         isa->port = strtoul(p+5, &p, 0);
282                 else if(cistrncmp(p, "irq=", 4) == 0)
283                         isa->irq = strtoul(p+4, &p, 0);
284                 else if(cistrncmp(p, "dma=", 4) == 0)
285                         isa->dma = strtoul(p+4, &p, 0);
286                 else if(cistrncmp(p, "mem=", 4) == 0)
287                         isa->mem = strtoul(p+4, &p, 0);
288                 else if(cistrncmp(p, "size=", 5) == 0)
289                         isa->size = strtoul(p+5, &p, 0);
290                 else if(cistrncmp(p, "freq=", 5) == 0)
291                         isa->freq = strtoul(p+5, &p, 0);
292         }
293         return 1;
294 }
295
296 /*
297  * the new kernel is already loaded at address `code'
298  * of size `size' and entry point `entry'.
299  */
300 void
301 reboot(void *entry, void *code, ulong size)
302 {
303         void (*f)(ulong, ulong, ulong);
304
305         writeconf();
306         cpushutdown();
307
308         /* turn off buffered serial console */
309         serialoq = nil;
310         kprintoq = nil;
311         screenputs = nil;
312
313         /* shutdown devices */
314         chandevshutdown();
315
316         /* call off the dog */
317         clockshutdown();
318
319         splhi();
320         intrsoff();
321
322         /* setup reboot trampoline function */
323         f = (void*)REBOOTADDR;
324         memmove(f, rebootcode, sizeof(rebootcode));
325         cacheuwbinv();
326         l2cacheuwbinv();
327
328         /* off we go - never to return */
329         (*f)(PADDR(entry), PADDR(code), size);
330 }
331
332 /*
333  *  starting place for first process
334  */
335 void
336 init0(void)
337 {
338         char buf[2*KNAMELEN], **sp;
339         int i;
340
341         dmatest();              /* needs `up' set, so can't do it earlier */
342         chandevinit();
343         i8250console();         /* might be redundant, but harmless */
344         if(serialoq == nil)
345                 panic("init0: nil serialoq");
346         normalprint = 1;
347
348         if(!waserror()){
349                 snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
350                 ksetenv("terminal", buf, 0);
351                 ksetenv("cputype", "arm", 0);
352                 if(cpuserver)
353                         ksetenv("service", "cpu", 0);
354                 else
355                         ksetenv("service", "terminal", 0);
356
357                 /* convert plan9.ini variables to #e and #ec */
358                 for(i = 0; i < nconf; i++) {
359                         ksetenv(confname[i], confval[i], 0);
360                         ksetenv(confname[i], confval[i], 1);
361                 }
362                 poperror();
363         }
364         kproc("alarm", alarmkproc, 0);
365
366         sp = (char**)(USTKTOP - sizeof(Tos) - 8 - sizeof(sp[0])*4);
367         sp[3] = sp[2] = sp[1] = nil;
368         strcpy(sp[0] = (char*)&sp[4], "boot");
369         touser((uintptr)sp);
370 }
371
372 Conf conf;                      /* XXX - must go - gag */
373
374 Confmem omapmem[nelem(conf.mem)] = {
375         /*
376          * Memory available to Plan 9:
377          */
378         { .base = PHYSDRAM, .limit = PHYSDRAM + Minmem, },
379 };
380 ulong memsize = Minmem;
381
382 static int
383 gotmem(uintptr sz)
384 {
385         uintptr addr;
386
387         addr = PHYSDRAM + sz - BY2WD;
388         mmuidmap(addr, 1);
389         if (probeaddr(addr) >= 0) {
390                 memsize = sz;
391                 return 0;
392         }
393         return -1;
394 }
395
396 void
397 confinit(void)
398 {
399         int i;
400         ulong kpages;
401         uintptr pa;
402         char *p;
403
404         /*
405          * Copy the physical memory configuration to Conf.mem.
406          */
407         if(nelem(omapmem) > nelem(conf.mem)){
408                 iprint("memory configuration botch\n");
409                 exit(1);
410         }
411         if((p = getconf("*maxmem")) != nil) {
412                 memsize = strtoul(p, 0, 0) - PHYSDRAM;
413                 if (memsize < 16*MB)            /* sanity */
414                         memsize = 16*MB;
415         }
416
417         /*
418          * see if all that memory exists; if not, find out how much does.
419          * trapinit must have been called first.
420          */
421         if (gotmem(memsize) < 0 && gotmem(256*MB) < 0 && gotmem(128*MB) < 0) {
422                 iprint("can't find any memory, assuming %dMB\n", Minmem / MB);
423                 memsize = Minmem;
424         }
425
426         omapmem[0].limit = PHYSDRAM + memsize;
427         memmove(conf.mem, omapmem, sizeof(omapmem));
428
429         conf.npage = 0;
430         pa = PADDR(PGROUND((uintptr)end));
431
432         /*
433          *  we assume that the kernel is at the beginning of one of the
434          *  contiguous chunks of memory and fits therein.
435          */
436         for(i=0; i<nelem(conf.mem); i++){
437                 /* take kernel out of allocatable space */
438                 if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
439                         conf.mem[i].base = pa;
440
441                 conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
442                 conf.npage += conf.mem[i].npage;
443         }
444
445         conf.upages = (conf.npage*80)/100;
446         conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
447
448         /* only one processor */
449         conf.nmach = 1;
450
451         /* set up other configuration parameters */
452         conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
453         if(cpuserver)
454                 conf.nproc *= 3;
455         if(conf.nproc > 2000)
456                 conf.nproc = 2000;
457         conf.nswap = conf.npage*3;
458         conf.nswppo = 4096;
459         conf.nimage = 200;
460
461         conf.copymode = 0;              /* copy on write */
462
463         /*
464          * Guess how much is taken by the large permanent
465          * datastructures. Mntcache and Mntrpc are not accounted for.
466          */
467         kpages = conf.npage - conf.upages;
468         kpages *= BY2PG;
469         kpages -= conf.upages*sizeof(Page)
470                 + conf.nproc*sizeof(Proc)
471                 + conf.nimage*sizeof(Image)
472                 + conf.nswap
473                 + conf.nswppo*sizeof(Page*);
474         mainmem->maxsize = kpages;
475         if(!cpuserver)
476                 /*
477                  * give terminals lots of image memory, too; the dynamic
478                  * allocation will balance the load properly, hopefully.
479                  * be careful with 32-bit overflow.
480                  */
481                 imagmem->maxsize = kpages;
482
483 //      archconfinit();
484 }
485
486 int
487 cmpswap(long *addr, long old, long new)
488 {
489         return cas32(addr, old, new);
490 }
491
492 void
493 setupwatchpts(Proc *, Watchpt *, int n)
494 {
495         if(n > 0)
496                 error("no watchpoints");
497 }