changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/9/bcm/main.c

changeset 4250: d819f0505c21
parent: a7cf12962171
child: 7e93ea0d48d1
author: cinap_lenrek@felloff.net
date: Sat, 07 Feb 2015 02:52:23 +0100
permissions: -rw-r--r--
description: kernel: reduce Page structure size by changing Page.cachectl[]

there are no kernels currently that do page coloring,
so the only use of cachectl[] is flushing the icache
(on arm and ppc).

on pc64, cachectl consumes 32 bytes in each page resulting
in over 200 megabytes of overhead for 32gb of ram with 4K
pages.

this change removes cachectl[] and adds txtflush ulong
that is set to ~0 by pio() to instruct putmmu() to flush
the icache.
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 "init.h"
9 #include <pool.h>
10 
11 #include "reboot.h"
12 
13 /* Firmware compatibility */
14 #define Minfirmrev 326770
15 #define Minfirmdate "22 Jul 2012"
16 
17 /*
18  * Where configuration info is left for the loaded programme.
19  */
20 #define BOOTARGS ((char*)CONFADDR)
21 #define BOOTARGSLEN (MACHADDR-CONFADDR)
22 #define MAXCONF 64
23 #define MAXCONFLINE 160
24 
25 uintptr kseg0 = KZERO;
26 Mach* machaddr[MAXMACH];
27 Conf conf;
28 ulong memsize = 128*1024*1024;
29 
30 /*
31  * Option arguments from the command line.
32  * oargv[0] is the boot file.
33  */
34 static int oargc;
35 static char* oargv[20];
36 static char oargb[128];
37 static int oargblen;
38 
39 static uintptr sp; /* XXX - must go - user stack of init proc */
40 
41 /* store plan9.ini contents here at least until we stash them in #ec */
42 static char confname[MAXCONF][KNAMELEN];
43 static char confval[MAXCONF][MAXCONFLINE];
44 static int nconf;
45 
46 typedef struct Atag Atag;
47 struct Atag {
48  u32int size; /* size of atag in words, including this header */
49  u32int tag; /* atag type */
50  union {
51  u32int data[1]; /* actually [size-2] */
52  /* AtagMem */
53  struct {
54  u32int size;
55  u32int base;
56  } mem;
57  /* AtagCmdLine */
58  char cmdline[1]; /* actually [4*(size-2)] */
59  };
60 };
61 
62 enum {
63  AtagNone = 0x00000000,
64  AtagCore = 0x54410001,
65  AtagMem = 0x54410002,
66  AtagCmdline = 0x54410009,
67 };
68 
69 static int
70 findconf(char *name)
71 {
72  int i;
73 
74  for(i = 0; i < nconf; i++)
75  if(cistrcmp(confname[i], name) == 0)
76  return i;
77  return -1;
78 }
79 
80 char*
81 getconf(char *name)
82 {
83  int i;
84 
85  i = findconf(name);
86  if(i >= 0)
87  return confval[i];
88  return nil;
89 }
90 
91 void
92 addconf(char *name, char *val)
93 {
94  int i;
95 
96  i = findconf(name);
97  if(i < 0){
98  if(val == nil || nconf >= MAXCONF)
99  return;
100  i = nconf++;
101  strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
102  }
103  strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
104 }
105 
106 static void
107 writeconf(void)
108 {
109  char *p, *q;
110  int n;
111 
112  p = getconfenv();
113 
114  if(waserror()) {
115  free(p);
116  nexterror();
117  }
118 
119  /* convert to name=value\n format */
120  for(q=p; *q; q++) {
121  q += strlen(q);
122  *q = '=';
123  q += strlen(q);
124  *q = '\n';
125  }
126  n = q - p + 1;
127  if(n >= BOOTARGSLEN)
128  error("kernel configuration too large");
129  memmove(BOOTARGS, p, n);
130  memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
131  poperror();
132  free(p);
133 }
134 
135 static void
136 plan9iniinit(char *s, int cmdline)
137 {
138  char *toks[MAXCONF];
139  int i, c, n;
140  char *v;
141 
142  if((c = *s) < ' ' || c >= 0x80)
143  return;
144  if(cmdline)
145  n = tokenize(s, toks, MAXCONF);
146  else
147  n = getfields(s, toks, MAXCONF, 1, "\n");
148  for(i = 0; i < n; i++){
149  if(toks[i][0] == '#')
150  continue;
151  v = strchr(toks[i], '=');
152  if(v == nil)
153  continue;
154  *v++ = '\0';
155  addconf(toks[i], v);
156  }
157 }
158 
159 static void
160 ataginit(Atag *a)
161 {
162  int n;
163 
164  if(a->tag != AtagCore){
165  plan9iniinit((char*)a, 0);
166  return;
167  }
168  while(a->tag != AtagNone){
169  switch(a->tag){
170  case AtagMem:
171  /* use only first bank */
172  if(conf.mem[0].limit == 0 && a->mem.size != 0){
173  memsize = a->mem.size;
174  conf.mem[0].base = a->mem.base;
175  conf.mem[0].limit = a->mem.base + memsize;
176  }
177  break;
178  case AtagCmdline:
179  n = (a->size * sizeof(u32int)) - offsetof(Atag, cmdline[0]);
180  if(a->cmdline + n < BOOTARGS + BOOTARGSLEN)
181  a->cmdline[n] = 0;
182  else
183  BOOTARGS[BOOTARGSLEN-1] = 0;
184  plan9iniinit(a->cmdline, 1);
185  break;
186  }
187  a = (Atag*)((u32int*)a + a->size);
188  }
189 }
190 
191 void
192 machinit(void)
193 {
194  m->machno = 0;
195  machaddr[m->machno] = m;
196 
197  m->ticks = 1;
198  m->perf.period = 1;
199 
200  conf.nmach = 1;
201 
202  active.machs = 1;
203  active.exiting = 0;
204 
205  up = nil;
206 }
207 
208 static void
209 optionsinit(char* s)
210 {
211  strecpy(oargb, oargb+sizeof(oargb), s);
212 
213  oargblen = strlen(oargb);
214  oargc = tokenize(oargb, oargv, nelem(oargv)-1);
215  oargv[oargc] = nil;
216 }
217 
218 void
219 gpiomeminit(void)
220 {
221  Physseg seg;
222  memset(&seg, 0, sizeof seg);
223  seg.attr = SG_PHYSICAL;
224  seg.name = "gpio";
225  seg.pa = (VIRTIO+0x200000);
226  seg.size = BY2PG;
227  addphysseg(&seg);
228 }
229 
230 
231 void
232 main(void)
233 {
234  extern char edata[], end[];
235  uint rev;
236 
237  okay(1);
238  m = (Mach*)MACHADDR;
239  memset(edata, 0, end - edata); /* clear bss */
240  machinit();
241  mmuinit1();
242 
243  optionsinit("/boot/boot boot");
244  quotefmtinstall();
245 
246  ataginit((Atag*)BOOTARGS);
247  confinit(); /* figures out amount of memory */
248  xinit();
249  uartconsinit();
250  screeninit();
251 
252  print("\nPlan 9 from Bell Labs\n");
253  rev = getfirmware();
254  print("firmware: rev %d\n", rev);
255  if(rev < Minfirmrev){
256  print("Sorry, firmware (start.elf) must be at least rev %d (%s)\n",
257  Minfirmrev, Minfirmdate);
258  for(;;)
259  ;
260  }
261  trapinit();
262  clockinit();
263  printinit();
264  timersinit();
265  cpuidprint();
266  archreset();
267 
268  procinit0();
269  initseg();
270  links();
271  chandevreset(); /* most devices are discovered here */
272  pageinit();
273  swapinit();
274  userinit();
275  gpiomeminit();
276  schedinit();
277  assert(0); /* shouldn't have returned */
278 }
279 
280 /*
281  * starting place for first process
282  */
283 void
284 init0(void)
285 {
286  int i;
287  char buf[2*KNAMELEN];
288 
289  up->nerrlab = 0;
290  coherence();
291  spllo();
292 
293  /*
294  * These are o.k. because rootinit is null.
295  * Then early kproc's will have a root and dot.
296  */
297  up->slash = namec("#/", Atodir, 0, 0);
298  pathclose(up->slash->path);
299  up->slash->path = newpath("/");
300  up->dot = cclone(up->slash);
301 
302  chandevinit();
303 
304  if(!waserror()){
305  snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
306  ksetenv("terminal", buf, 0);
307  ksetenv("cputype", "arm", 0);
308  if(cpuserver)
309  ksetenv("service", "cpu", 0);
310  else
311  ksetenv("service", "terminal", 0);
312  snprint(buf, sizeof(buf), "-a %s", getethermac());
313  ksetenv("etherargs", buf, 0);
314 
315  /* convert plan9.ini variables to #e and #ec */
316  for(i = 0; i < nconf; i++) {
317  ksetenv(confname[i], confval[i], 0);
318  ksetenv(confname[i], confval[i], 1);
319  }
320  poperror();
321  }
322  kproc("alarm", alarmkproc, 0);
323  touser(sp);
324  assert(0); /* shouldn't have returned */
325 }
326 
327 static void
328 bootargs(uintptr base)
329 {
330  int i;
331  ulong ssize;
332  char **av, *p;
333 
334  /*
335  * Push the boot args onto the stack.
336  * The initial value of the user stack must be such
337  * that the total used is larger than the maximum size
338  * of the argument list checked in syscall.
339  */
340  i = oargblen+1;
341  p = UINT2PTR(STACKALIGN(base + BY2PG - sizeof(Tos) - i));
342  memmove(p, oargb, i);
343 
344  /*
345  * Now push the argv pointers.
346  * The code jumped to by touser in lproc.s expects arguments
347  * main(char* argv0, ...)
348  * and calls
349  * startboot("/boot/boot", &argv0)
350  * not the usual (int argc, char* argv[])
351  */
352  av = (char**)(p - (oargc+1)*sizeof(char*));
353  ssize = base + BY2PG - PTR2UINT(av);
354  for(i = 0; i < oargc; i++)
355  *av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
356  *av = nil;
357  sp = USTKTOP - ssize;
358 }
359 
360 /*
361  * create the first process
362  */
363 void
364 userinit(void)
365 {
366  Proc *p;
367  Segment *s;
368  KMap *k;
369  Page *pg;
370 
371  /* no processes yet */
372  up = nil;
373 
374  p = newproc();
375  p->pgrp = newpgrp();
376  p->egrp = smalloc(sizeof(Egrp));
377  p->egrp->ref = 1;
378  p->fgrp = dupfgrp(nil);
379  p->rgrp = newrgrp();
380  p->procmode = 0640;
381 
382  kstrdup(&eve, "");
383  kstrdup(&p->text, "*init*");
384  kstrdup(&p->user, eve);
385 
386  /*
387  * Kernel Stack
388  */
389  p->sched.pc = PTR2UINT(init0);
390  p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
391  p->sched.sp = STACKALIGN(p->sched.sp);
392 
393  /*
394  * User Stack
395  *
396  * Technically, newpage can't be called here because it
397  * should only be called when in a user context as it may
398  * try to sleep if there are no pages available, but that
399  * shouldn't be the case here.
400  */
401  s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
402  s->flushme++;
403  p->seg[SSEG] = s;
404  pg = newpage(1, 0, USTKTOP-BY2PG);
405  segpage(s, pg);
406  k = kmap(pg);
407  bootargs(VA(k));
408  kunmap(k);
409 
410  /*
411  * Text
412  */
413  s = newseg(SG_TEXT, UTZERO, 1);
414  p->seg[TSEG] = s;
415  pg = newpage(1, 0, UTZERO);
416  pg->txtflush = ~0;
417  segpage(s, pg);
418  k = kmap(s->map[0]->pages[0]);
419  memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
420  kunmap(k);
421 
422  ready(p);
423 }
424 
425 void
426 confinit(void)
427 {
428  int i, userpcnt;
429  ulong kpages;
430  uintptr pa;
431  char *p;
432 
433  if(p = getconf("service")){
434  if(strcmp(p, "cpu") == 0)
435  cpuserver = 1;
436  else if(strcmp(p,"terminal") == 0)
437  cpuserver = 0;
438  }
439 
440  if(p = getconf("*kernelpercent"))
441  userpcnt = 100 - strtol(p, 0, 0);
442  else
443  userpcnt = 0;
444 
445  if((p = getconf("*maxmem")) != nil){
446  memsize = strtoul(p, 0, 0) - PHYSDRAM;
447  if (memsize < 16*MB) /* sanity */
448  memsize = 16*MB;
449  }
450 
451  getramsize(&conf.mem[0]);
452  if(conf.mem[0].limit == 0){
453  conf.mem[0].base = PHYSDRAM;
454  conf.mem[0].limit = PHYSDRAM + memsize;
455  }else if(p != nil)
456  conf.mem[0].limit = conf.mem[0].base + memsize;
457 
458  conf.npage = 0;
459  pa = PADDR(PGROUND(PTR2UINT(end)));
460 
461  /*
462  * we assume that the kernel is at the beginning of one of the
463  * contiguous chunks of memory and fits therein.
464  */
465  for(i=0; i<nelem(conf.mem); i++){
466  /* take kernel out of allocatable space */
467  if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
468  conf.mem[i].base = pa;
469 
470  conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
471  conf.npage += conf.mem[i].npage;
472  }
473 
474  if(userpcnt < 10)
475  userpcnt = 60 + cpuserver*10;
476  kpages = conf.npage - (conf.npage*userpcnt)/100;
477 
478  /*
479  * can't go past the end of virtual memory
480  * (ulong)-KZERO is 2^32 - KZERO
481  */
482  if(kpages > ((ulong)-KZERO)/BY2PG)
483  kpages = ((ulong)-KZERO)/BY2PG;
484 
485  conf.upages = conf.npage - kpages;
486  conf.ialloc = (kpages/2)*BY2PG;
487 
488  /* only one processor */
489  conf.nmach = 1;
490 
491  /* set up other configuration parameters */
492  conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
493  if(cpuserver)
494  conf.nproc *= 3;
495  if(conf.nproc > 2000)
496  conf.nproc = 2000;
497  conf.nswap = conf.npage*3;
498  conf.nswppo = 4096;
499  conf.nimage = 200;
500 
501  conf.copymode = 0; /* copy on write */
502 
503  /*
504  * Guess how much is taken by the large permanent
505  * datastructures. Mntcache and Mntrpc are not accounted for.
506  */
507  kpages = conf.npage - conf.upages;
508  kpages *= BY2PG;
509  kpages -= conf.upages*sizeof(Page)
510  + conf.nproc*sizeof(Proc)
511  + conf.nimage*sizeof(Image)
512  + conf.nswap
513  + conf.nswppo*sizeof(Page*);
514  mainmem->maxsize = kpages;
515  if(!cpuserver)
516  /*
517  * give terminals lots of image memory, too; the dynamic
518  * allocation will balance the load properly, hopefully.
519  * be careful with 32-bit overflow.
520  */
521  imagmem->maxsize = kpages;
522 
523 }
524 
525 static void
526 shutdown(int ispanic)
527 {
528  int ms, once;
529 
530  lock(&active);
531  if(ispanic)
532  active.ispanic = ispanic;
533  else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
534  active.ispanic = 0;
535  once = active.machs & (1<<m->machno);
536  active.machs &= ~(1<<m->machno);
537  active.exiting = 1;
538  unlock(&active);
539 
540  if(once)
541  iprint("cpu%d: exiting\n", m->machno);
542  spllo();
543  for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
544  delay(TK2MS(2));
545  if(active.machs == 0 && consactive() == 0)
546  break;
547  }
548  delay(1000);
549 }
550 
551 /*
552  * exit kernel either on a panic or user request
553  */
554 void
555 exit(int code)
556 {
557  shutdown(code);
558  splfhi();
559  archreboot();
560 }
561 
562 /*
563  * stub for ../omap/devether.c
564  */
565 int
566 isaconfig(char *class, int ctlrno, ISAConf *isa)
567 {
568  USED(ctlrno);
569  USED(isa);
570  return strcmp(class, "ether") == 0;
571 }
572 
573 /*
574  * the new kernel is already loaded at address `code'
575  * of size `size' and entry point `entry'.
576  */
577 void
578 reboot(void *entry, void *code, ulong size)
579 {
580  void (*f)(ulong, ulong, ulong);
581 
582  print("starting reboot...");
583  writeconf();
584  shutdown(0);
585 
586  /*
587  * should be the only processor running now
588  */
589 
590  print("reboot entry %#lux code %#lux size %ld\n",
591  PADDR(entry), PADDR(code), size);
592  delay(100);
593 
594  /* turn off buffered serial console */
595  serialoq = nil;
596  kprintoq = nil;
597  screenputs = nil;
598 
599  /* shutdown devices */
600  chandevshutdown();
601 
602  /* stop the clock (and watchdog if any) */
603  clockshutdown();
604 
605  splfhi();
606  intrsoff();
607 
608  /* setup reboot trampoline function */
609  f = (void*)REBOOTADDR;
610  memmove(f, rebootcode, sizeof(rebootcode));
611  cacheuwbinv();
612 
613  /* off we go - never to return */
614  (*f)(PADDR(entry), PADDR(code), size);
615 
616  iprint("loaded kernel returned!\n");
617  delay(1000);
618  archreboot();
619 }
620 
621 int
622 cmpswap(long *addr, long old, long new)
623 {
624  return cas32(addr, old, new);
625 }