changelog shortlog tags branches changeset files revisions annotate raw help

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

changeset 6851: 817828d0da99
parent: f80792d28e0e
child: 01468da33a6e
author: cinap_lenrek@felloff.net
date: Sun, 28 Oct 2018 06:16:10 +0100
permissions: -rw-r--r--
description: bcm: simplify reboot code

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