changelog shortlog tags branches changeset files revisions annotate raw help

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

changeset 2503: e48d4208f76f
parent: f7c2fc5e9dd8
child: 4b8b4a29def2
author: cinap_lenrek@gmx.de
date: Sun, 14 Apr 2013 16:28:54 +0200
permissions: -rw-r--r--
description: reduce software cursor flickering

the software cursor starts flickering and reacts bumby if a process
spends most of its time with drawlock acquired because the timer interrupt
thats supposed to redraw the cursor fails to acquire the lock at the time
the timer fires.

instead of trying to draw the cursor on the screen from a timer interrupt
30 times per second, devmouse now creates a process calling cursoron() and
cursoroff() when the cursor needs to be redrawn. this allows the swcursor
to schedule a redraw while holding the drawlock in swcursoravoid() and
cursoron()/cursoroff() are now able to wait for a qlock (drawlock) because
they get called from process context.

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