changelog shortlog tags branches changeset files revisions annotate raw help

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

changeset 2323: f7c2fc5e9dd8
child: e48d4208f76f
author: cinap_lenrek@gmx.de
date: Sat, 26 Jan 2013 17:33:56 +0100
permissions: -rw-r--r--
description: add raspberry pi kernel (from sources)
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 main(void)
220 {
221  extern char edata[], end[];
222  uint rev;
223 
224  okay(1);
225  m = (Mach*)MACHADDR;
226  memset(edata, 0, end - edata); /* clear bss */
227  machinit();
228  mmuinit1();
229 
230  optionsinit("/boot/boot boot");
231  quotefmtinstall();
232 
233  ataginit((Atag*)BOOTARGS);
234  confinit(); /* figures out amount of memory */
235  xinit();
236  uartconsinit();
237  screeninit();
238 
239  print("\nPlan 9 from Bell Labs\n");
240  rev = getfirmware();
241  print("firmware: rev %d\n", rev);
242  if(rev < Minfirmrev){
243  print("Sorry, firmware (start.elf) must be at least rev %d (%s)\n",
244  Minfirmrev, Minfirmdate);
245  for(;;)
246  ;
247  }
248  trapinit();
249  clockinit();
250  printinit();
251  timersinit();
252  if(conf.monitor)
253  swcursorinit();
254  cpuidprint();
255  archreset();
256 
257  procinit0();
258  initseg();
259  links();
260  chandevreset(); /* most devices are discovered here */
261  pageinit();
262  swapinit();
263  userinit();
264  schedinit();
265  assert(0); /* shouldn't have returned */
266 }
267 
268 /*
269  * starting place for first process
270  */
271 void
272 init0(void)
273 {
274  int i;
275  char buf[2*KNAMELEN];
276 
277  up->nerrlab = 0;
278  coherence();
279  spllo();
280 
281  /*
282  * These are o.k. because rootinit is null.
283  * Then early kproc's will have a root and dot.
284  */
285  up->slash = namec("#/", Atodir, 0, 0);
286  pathclose(up->slash->path);
287  up->slash->path = newpath("/");
288  up->dot = cclone(up->slash);
289 
290  chandevinit();
291 
292  if(!waserror()){
293  snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
294  ksetenv("terminal", buf, 0);
295  ksetenv("cputype", "arm", 0);
296  if(cpuserver)
297  ksetenv("service", "cpu", 0);
298  else
299  ksetenv("service", "terminal", 0);
300  snprint(buf, sizeof(buf), "-a %s", getethermac());
301  ksetenv("etherargs", buf, 0);
302 
303  /* convert plan9.ini variables to #e and #ec */
304  for(i = 0; i < nconf; i++) {
305  ksetenv(confname[i], confval[i], 0);
306  ksetenv(confname[i], confval[i], 1);
307  }
308  poperror();
309  }
310  kproc("alarm", alarmkproc, 0);
311  touser(sp);
312  assert(0); /* shouldn't have returned */
313 }
314 
315 static void
316 bootargs(uintptr base)
317 {
318  int i;
319  ulong ssize;
320  char **av, *p;
321 
322  /*
323  * Push the boot args onto the stack.
324  * The initial value of the user stack must be such
325  * that the total used is larger than the maximum size
326  * of the argument list checked in syscall.
327  */
328  i = oargblen+1;
329  p = UINT2PTR(STACKALIGN(base + BY2PG - sizeof(Tos) - i));
330  memmove(p, oargb, i);
331 
332  /*
333  * Now push the argv pointers.
334  * The code jumped to by touser in lproc.s expects arguments
335  * main(char* argv0, ...)
336  * and calls
337  * startboot("/boot/boot", &argv0)
338  * not the usual (int argc, char* argv[])
339  */
340  av = (char**)(p - (oargc+1)*sizeof(char*));
341  ssize = base + BY2PG - PTR2UINT(av);
342  for(i = 0; i < oargc; i++)
343  *av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
344  *av = nil;
345  sp = USTKTOP - ssize;
346 }
347 
348 /*
349  * create the first process
350  */
351 void
352 userinit(void)
353 {
354  Proc *p;
355  Segment *s;
356  KMap *k;
357  Page *pg;
358 
359  /* no processes yet */
360  up = nil;
361 
362  p = newproc();
363  p->pgrp = newpgrp();
364  p->egrp = smalloc(sizeof(Egrp));
365  p->egrp->ref = 1;
366  p->fgrp = dupfgrp(nil);
367  p->rgrp = newrgrp();
368  p->procmode = 0640;
369 
370  kstrdup(&eve, "");
371  kstrdup(&p->text, "*init*");
372  kstrdup(&p->user, eve);
373 
374  /*
375  * Kernel Stack
376  */
377  p->sched.pc = PTR2UINT(init0);
378  p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
379  p->sched.sp = STACKALIGN(p->sched.sp);
380 
381  /*
382  * User Stack
383  *
384  * Technically, newpage can't be called here because it
385  * should only be called when in a user context as it may
386  * try to sleep if there are no pages available, but that
387  * shouldn't be the case here.
388  */
389  s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
390  s->flushme++;
391  p->seg[SSEG] = s;
392  pg = newpage(1, 0, USTKTOP-BY2PG);
393  segpage(s, pg);
394  k = kmap(pg);
395  bootargs(VA(k));
396  kunmap(k);
397 
398  /*
399  * Text
400  */
401  s = newseg(SG_TEXT, UTZERO, 1);
402  p->seg[TSEG] = s;
403  pg = newpage(1, 0, UTZERO);
404  memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
405  segpage(s, pg);
406  k = kmap(s->map[0]->pages[0]);
407  memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
408  kunmap(k);
409 
410  ready(p);
411 }
412 
413 void
414 confinit(void)
415 {
416  int i;
417  ulong kpages;
418  uintptr pa;
419  char *p;
420 
421  if(0 && (p = getconf("service")) != nil){
422  if(strcmp(p, "cpu") == 0)
423  cpuserver = 1;
424  else if(strcmp(p,"terminal") == 0)
425  cpuserver = 0;
426  }
427  if((p = getconf("*maxmem")) != nil){
428  memsize = strtoul(p, 0, 0) - PHYSDRAM;
429  if (memsize < 16*MB) /* sanity */
430  memsize = 16*MB;
431  }
432 
433  getramsize(&conf.mem[0]);
434  if(conf.mem[0].limit == 0){
435  conf.mem[0].base = PHYSDRAM;
436  conf.mem[0].limit = PHYSDRAM + memsize;
437  }else if(p != nil)
438  conf.mem[0].limit = conf.mem[0].base + memsize;
439 
440  conf.npage = 0;
441  pa = PADDR(PGROUND(PTR2UINT(end)));
442 
443  /*
444  * we assume that the kernel is at the beginning of one of the
445  * contiguous chunks of memory and fits therein.
446  */
447  for(i=0; i<nelem(conf.mem); i++){
448  /* take kernel out of allocatable space */
449  if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
450  conf.mem[i].base = pa;
451 
452  conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
453  conf.npage += conf.mem[i].npage;
454  }
455 
456  conf.upages = (conf.npage*80)/100;
457  conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
458 
459  /* only one processor */
460  conf.nmach = 1;
461 
462  /* set up other configuration parameters */
463  conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
464  if(cpuserver)
465  conf.nproc *= 3;
466  if(conf.nproc > 2000)
467  conf.nproc = 2000;
468  conf.nswap = conf.npage*3;
469  conf.nswppo = 4096;
470  conf.nimage = 200;
471 
472  conf.copymode = 0; /* copy on write */
473 
474  /*
475  * Guess how much is taken by the large permanent
476  * datastructures. Mntcache and Mntrpc are not accounted for
477  * (probably ~300KB).
478  */
479  kpages = conf.npage - conf.upages;
480  kpages *= BY2PG;
481  kpages -= conf.upages*sizeof(Page)
482  + conf.nproc*sizeof(Proc)
483  + conf.nimage*sizeof(Image)
484  + conf.nswap
485  + conf.nswppo*sizeof(Page);
486  mainmem->maxsize = kpages;
487  if(!cpuserver)
488  /*
489  * give terminals lots of image memory, too; the dynamic
490  * allocation will balance the load properly, hopefully.
491  * be careful with 32-bit overflow.
492  */
493  imagmem->maxsize = kpages;
494 
495 }
496 
497 static void
498 shutdown(int ispanic)
499 {
500  int ms, once;
501 
502  lock(&active);
503  if(ispanic)
504  active.ispanic = ispanic;
505  else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
506  active.ispanic = 0;
507  once = active.machs & (1<<m->machno);
508  active.machs &= ~(1<<m->machno);
509  active.exiting = 1;
510  unlock(&active);
511 
512  if(once)
513  iprint("cpu%d: exiting\n", m->machno);
514  spllo();
515  for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
516  delay(TK2MS(2));
517  if(active.machs == 0 && consactive() == 0)
518  break;
519  }
520  delay(1000);
521 }
522 
523 /*
524  * exit kernel either on a panic or user request
525  */
526 void
527 exit(int code)
528 {
529  shutdown(code);
530  splfhi();
531  archreboot();
532 }
533 
534 /*
535  * stub for ../omap/devether.c
536  */
537 int
538 isaconfig(char *class, int ctlrno, ISAConf *isa)
539 {
540  USED(ctlrno);
541  USED(isa);
542  return strcmp(class, "ether") == 0;
543 }
544 
545 /*
546  * the new kernel is already loaded at address `code'
547  * of size `size' and entry point `entry'.
548  */
549 void
550 reboot(void *entry, void *code, ulong size)
551 {
552  void (*f)(ulong, ulong, ulong);
553 
554  print("starting reboot...");
555  writeconf();
556  shutdown(0);
557 
558  /*
559  * should be the only processor running now
560  */
561 
562  print("reboot entry %#lux code %#lux size %ld\n",
563  PADDR(entry), PADDR(code), size);
564  delay(100);
565 
566  /* turn off buffered serial console */
567  serialoq = nil;
568  kprintoq = nil;
569  screenputs = nil;
570 
571  /* shutdown devices */
572  chandevshutdown();
573 
574  /* stop the clock (and watchdog if any) */
575  clockshutdown();
576 
577  splfhi();
578  intrsoff();
579 
580  /* setup reboot trampoline function */
581  f = (void*)REBOOTADDR;
582  memmove(f, rebootcode, sizeof(rebootcode));
583  cacheuwbinv();
584 
585  /* off we go - never to return */
586  (*f)(PADDR(entry), PADDR(code), size);
587 
588  iprint("loaded kernel returned!\n");
589  delay(1000);
590  archreboot();
591 }
592 
593 int
594 cmpswap(long *addr, long old, long new)
595 {
596  return cas32(addr, old, new);
597 }