1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "ureg.h"
8 #include "../ip/ip.h"
9 #include "version.h"
10
11 #define MAXCONF 32
12
13 extern ulong kerndate;
14 extern int cflag;
15 int remotedebug;
16
17 extern int main_pool_pcnt;
18 extern int heap_pool_pcnt;
19 extern int image_pool_pcnt;
20
21 char *confname[MAXCONF];
22 char *confval[MAXCONF];
23 int nconf;
24
25 void addconf(char *, char *);
26 void eepromscan(void);
27
28 static void
options(void)29 options(void)
30 {
31 // nconf = archconfval(confname, confval, sizeof(confname));
32 }
33
34 void
doc(char * m)35 doc(char *m)
36 {
37 USED(m);
38 iprint("%s...\n", m);
39 }
40
41 void
idoc(char * m)42 idoc(char *m)
43 {
44 uartputs(m, strlen(m));
45 }
46
47 static void
poolsizeinit(void)48 poolsizeinit(void)
49 {
50 ulong nb;
51
52 nb = conf.npage*BY2PG;
53 poolsize(mainmem, (nb*main_pool_pcnt)/100, 0);
54 poolsize(heapmem, (nb*heap_pool_pcnt)/100, 0);
55 poolsize(imagmem, (nb*image_pool_pcnt)/100, 1);
56 }
57
58 static void
serialconsole(void)59 serialconsole(void)
60 {
61 char *p;
62 int port, baud;
63
64 p = getconf("console");
65 if(p == nil)
66 p = "0";
67 if(p != nil && !remotedebug){
68 port = strtol(p, nil, 0);
69 baud = 115200;
70 p = getconf("baud");
71 if(p != nil){
72 baud = strtol(p, nil, 0);
73 if(baud < 9600)
74 baud = 9600;
75 }
76 uartspecial(port, baud, &kbdq, &printq, kbdcr2nl);
77 }
78 }
79
80 void
main(void)81 main(void)
82 {
83 idoc("machinit...\n");
84 machinit();
85 idoc("options...\n");
86 compiledcr();
87 options();
88 // archinit();
89 quotefmtinstall();
90 idoc("confinit...\n");
91 confinit();
92 xinit();
93 poolsizeinit();
94 poolinit();
95 idoc("trapinit...\n");
96 trapinit();
97 mmuinit();
98 ioinit();
99 printinit();
100 uartinstall();
101 serialconsole();
102 pcimapinit();
103 eepromscan();
104 doc("clockinit");
105 clockinit();
106 doc("procinit");
107 procinit();
108 cpuidprint();
109 doc("links");
110 links();
111 doc("chandevreset");
112 chandevreset();
113
114 eve = strdup("inferno");
115
116 print("\nInferno %s\n", VERSION);
117 print("Vita Nuova\n");
118 print("conf %s (%lud) jit %d\n\n",conffile, kerndate, cflag);
119
120 doc("userinit");
121 userinit();
122 doc("schedinit");
123 schedinit();
124 }
125
126 //ccdv=1 cbdv=2 opdv=2 epdv=3 mpdv=1 ppdv=2
127
128 void
machinit(void)129 machinit(void)
130 {
131 int n;
132
133 n = m->machno;
134 memset(m, 0, sizeof(Mach));
135 m->machno = n;
136 m->mmask = 1<<m->machno;
137 m->cputype = getpvr()>>16;
138 m->delayloop = 20000; /* initial estimate only; set by clockinit */
139 m->speed = 266; /* initial estimate only; set by archinit */
140 m->cpuhz = 266333333;
141 m->vcohz = 799000000;
142 m->pllhz = 266333333;
143 m->plbhz = 133166666;
144 m->opbhz = 66600000;
145 m->epbhz = 44*MHz;
146 m->pcihz = 66600000;
147 m->clockgen = m->cpuhz; /* it's the internal cpu clock */
148 }
149
150 void
init0(void)151 init0(void)
152 {
153 Osenv *o;
154 int i;
155 char buf[2*KNAMELEN];
156
157 up->nerrlab = 0;
158
159 spllo();
160
161 if(waserror())
162 panic("init0");
163 /*
164 * These are o.k. because rootinit is null.
165 * Then early kproc's will have a root and dot.
166 */
167 o = up->env;
168 o->pgrp->slash = namec("#/", Atodir, 0, 0);
169 cnameclose(o->pgrp->slash->name);
170 o->pgrp->slash->name = newcname("/");
171 o->pgrp->dot = cclone(o->pgrp->slash);
172
173 chandevinit();
174
175 if(!waserror()){
176 ksetenv("cputype", "power", 0);
177 snprint(buf, sizeof(buf), "power %s", conffile);
178 ksetenv("terminal", buf, 0);
179 poperror();
180 }
181 for(i = 0; i < nconf; i++)
182 if(confname[i][0] != '*'){
183 if(!waserror()){
184 ksetenv(confname[i], confval[i], 0);
185 poperror();
186 }
187 }
188
189 poperror();
190 disinit("/osinit.dis");
191 }
192
193 void
userinit(void)194 userinit(void)
195 {
196 Proc *p;
197 Osenv *o;
198
199 p = newproc();
200 o = p->env;
201
202 o->fgrp = newfgrp(nil);
203 o->pgrp = newpgrp();
204 o->egrp = newegrp();
205 kstrdup(&o->user, eve);
206
207 strcpy(p->text, "interp");
208
209 /*
210 * Kernel Stack
211 */
212 p->sched.pc = (ulong)init0;
213 p->sched.sp = (ulong)p->kstack+KSTACK;
214
215 ready(p);
216 }
217
218 Conf conf;
219
220 void
addconf(char * name,char * val)221 addconf(char *name, char *val)
222 {
223 if(nconf >= MAXCONF)
224 return;
225 confname[nconf] = name;
226 confval[nconf] = val;
227 nconf++;
228 }
229
230 char*
getconf(char * name)231 getconf(char *name)
232 {
233 int i;
234
235 for(i = 0; i < nconf; i++)
236 if(cistrcmp(confname[i], name) == 0)
237 return confval[i];
238 return 0;
239 }
240
241 void
confinit(void)242 confinit(void)
243 {
244 char *p;
245 int pcnt;
246
247
248 if(p = getconf("*kernelpercent"))
249 pcnt = 100 - strtol(p, 0, 0);
250 else
251 pcnt = 0;
252
253 archconfinit();
254
255 conf.npage = conf.npage0 + conf.npage1;
256 if(pcnt < 10)
257 pcnt = 70;
258 conf.ialloc = (((conf.npage*(100-pcnt))/100)/2)*BY2PG;
259
260 conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
261 conf.nmach = MAXMACH;
262
263 }
264
265 static void
twinkle(void)266 twinkle(void)
267 {
268 if(m->ticks%MS2TK(1000) == 0)
269 ((Gpioregs*)PHYSGPIO)->or ^= 1<<31;
270 }
271
272 void (*archclocktick)(void) = twinkle;
273
274 void
exit(int ispanic)275 exit(int ispanic)
276 {
277 up = 0;
278 spllo();
279 print("cpu %d exiting\n", m->machno);
280
281 /* Shutdown running devices */
282 chandevshutdown();
283
284 delay(1000);
285 splhi();
286 if(ispanic)
287 for(;;);
288 archreboot();
289 }
290
291 void
reboot(void)292 reboot(void)
293 {
294 exit(0);
295 }
296
297 void
halt(void)298 halt(void)
299 {
300 print("cpu halted\n");
301 microdelay(1000);
302 for(;;)
303 ;
304 }
305
306 /*
307 * kept in case it's needed for PCI/ISA devices
308 */
309 int
isaconfig(char * class,int ctlrno,ISAConf * isa)310 isaconfig(char *class, int ctlrno, ISAConf *isa)
311 {
312 char cc[KNAMELEN], *p;
313 int i;
314
315 snprint(cc, sizeof cc, "%s%d", class, ctlrno);
316 p = getconf(cc);
317 if(p == nil)
318 return 0;
319
320 isa->nopt = tokenize(p, isa->opt, NISAOPT);
321 for(i = 0; i < isa->nopt; i++){
322 p = isa->opt[i];
323 if(cistrncmp(p, "type=", 5) == 0)
324 isa->type = p + 5;
325 else if(cistrncmp(p, "port=", 5) == 0)
326 isa->port = strtoul(p+5, &p, 0);
327 else if(cistrncmp(p, "irq=", 4) == 0)
328 isa->irq = strtoul(p+4, &p, 0);
329 else if(cistrncmp(p, "mem=", 4) == 0)
330 isa->mem = strtoul(p+4, &p, 0);
331 else if(cistrncmp(p, "size=", 5) == 0)
332 isa->size = strtoul(p+5, &p, 0);
333 else if(cistrncmp(p, "freq=", 5) == 0)
334 isa->freq = strtoul(p+5, &p, 0);
335 else if(cistrncmp(p, "dma=", 4) == 0)
336 isa->dma = strtoul(p+4, &p, 0);
337 }
338 return 1;
339 }
340
341 /*
342 * Save the mach dependent part of the process state.
343 */
344 void
procsave(Proc *)345 procsave(Proc*)
346 {
347 }
348
349 void
idlehands(void)350 idlehands(void)
351 {
352 putmsr(getmsr() | MSR_WE | MSR_EE | MSR_CE); /* MSR_DE as well? */
353 }
354
355 /* stubs */
356 void
setfsr(ulong)357 setfsr(ulong)
358 {
359 }
360
361 ulong
getfsr()362 getfsr()
363 {
364 return 0;
365 }
366
367 void
setfcr(ulong)368 setfcr(ulong)
369 {
370 }
371
372 ulong
getfcr()373 getfcr()
374 {
375 return 0;
376 }
377
378 /*
379 * some of this is possibly ice-cube specific
380 */
381
382 enum {
383 Cpc0Pllmr0= 0xF0, /* PLL mode register 0 */
384 Cpc0Boot= 0xF1, /* clock status */
385 Cpc0Pllmr1= 0xF4, /* PLL mode register 1 */
386 Cpc0Srr= 0xF6, /* PCI soft reset */
387 Cpc0PCI= 0xF9, /* PCI control */
388 };
389 /*
390 00f0 = 00011101
391 00f1 = 00000025
392 00f2 = 00000000
393 00f3 = 00000000
394 00f4 = 8085523e
395 00f5 = 00000017
396 00f6 = 00000000
397 ccdv=1 cbdv=2 opdv=2 epdv=3 mpdv=1 ppdv=2
398 fbmul=8 fwdva=5 fwdvb=5 tun=257 m=40
399 */
400 void
archconfinit(void)401 archconfinit(void)
402 {
403 ulong ktop;
404
405 conf.npage0 = (32*1024*1024)/BY2PG;
406 conf.base0 = 0;
407 ktop = PGROUND((ulong)end);
408 ktop = PADDR(ktop) - conf.base0;
409 conf.npage0 -= ktop/BY2PG;
410 conf.base0 += ktop;
411
412 {int i; for(i=0xF0; i<=0xF6; i++){iprint("%.4ux = %.8lux\n", i, getdcr(i));}}
413 {
414 int ccdv, cbdv, opdv, epdv, mpdv, ppdv;
415 int fbmul, fwdva, fwdvb, tun;
416 ulong mr0, mr1;
417
418 mr0 = getdcr(Cpc0Pllmr0);
419 ccdv = ((mr0>>20)&3)+1;
420 cbdv = ((mr0>>16)&3)+1;
421 opdv = ((mr0>>12)&3)+1;
422 epdv = ((mr0>>8)&3)+2;
423 mpdv = ((mr0>>4)&3)+1;
424 ppdv = (mr0&3)+1;
425 iprint("ccdv=%d cbdv=%d opdv=%d epdv=%d mpdv=%d ppdv=%d\n",
426 ccdv, cbdv, opdv, epdv, mpdv, ppdv);
427 mr1 = getdcr(Cpc0Pllmr1);
428 fbmul = (mr1>>20) & 0xF;
429 if(fbmul == 0)
430 fbmul = 16;
431 fwdva = (mr1>>16) & 7;
432 if(fwdva == 0)
433 fwdva = 8;
434 fwdvb = (mr1>>12) & 7;
435 if(fwdvb == 0)
436 fwdvb = 8;
437 tun = mr0 & 0x3FF;
438 iprint("fbmul=%d fwdva=%d fwdvb=%d tun=%d m=%d\n",
439 fbmul, fwdva, fwdvb, tun, fbmul*fwdva);
440 }
441 }
442
443 void
archreboot(void)444 archreboot(void)
445 {
446 putevpr(~0);
447 firmware(0);
448 for(;;);
449 }
450
451 void
clockcheck(void)452 clockcheck(void)
453 {
454 }
455
456 void
cpuidprint(void)457 cpuidprint(void)
458 {
459 iprint("PowerPC 405EP pvr=%8.8lux\n", getpvr());
460 /* TO DO */
461 }
462
463 #include "../port/flashif.h"
464
465 /*
466 * for devflash.c:/^flashreset
467 * retrieve flash type, virtual base and length and return 0;
468 * return -1 on error (no flash)
469 */
470 int
archflashreset(int bank,Flash * f)471 archflashreset(int bank, Flash *f)
472 {
473 switch(bank){
474 case 0:
475 f->type = "AMD29F0x0"; /* not right, but will do for now */
476 f->addr = (void*)PHYSFLASH;
477 f->size = FLASHSIZE;
478 f->width = 2;
479 return 0;
480 case 1:
481 f->type = "nand";
482 f->addr = (void*)PHYSNAND;
483 f->size = 0; /* done by probe */
484 f->width = 1;
485 return 0;
486 default:
487 return -1;
488 }
489 }
490
491 void
archflashwp(Flash *,int)492 archflashwp(Flash*, int)
493 {
494 }
495
496 #include "../port/netif.h"
497 #include "etherif.h"
498
499 enum {
500 /* EMAC-PHY control, tucked away in CPC0 */
501 Cpc0Epctl= 0xF3, /* EMAC-PHY ctl */
502
503 E0Nf= 1<<31, /* Emac0 noise filter enable */
504 E1Nf= 1<<30, /* Emac1 noise filter enable */
505 E1pr= 1<<7, /* Emac1 packet reject is active high */
506 E0pr= 1<<6, /* Emac 0 packet reject is active high */
507 E1rm= 1<<5, /* enable Emac 1 packet removal */
508 E0rm= 1<<4, /* enable Emac 0 packet removal */
509 E1pci= 1<<1, /* Emac 1 clock source is Tx clock output (loopback) */
510 E0pci= 1<<0, /* Emac 0 clock source is Tx clock output (loopback) */
511 };
512
513 int
archether(int ctlno,Ether * ether)514 archether(int ctlno, Ether *ether)
515 {
516 char name[KNAMELEN], *p;
517 int s;
518
519 if(ctlno > 1)
520 return -1;
521 ether->type = "EMAC";
522 ether->port = ctlno;
523 if(ctlno != 0)
524 snprint(name, sizeof(name), "eth%daddr", ctlno);
525 else
526 strcpy(name, "ethaddr");
527 p = getconf(name);
528 if(p == 0){
529 iprint("ether%d: no %s in EEPROM env\n", ctlno, name);
530 return -1;
531 }
532 parsemac(ether->ea, p, Eaddrlen);
533 s = splhi();
534 putdcr(Cpc0Epctl, getdcr(Cpc0Epctl) | (ctlno?E1Nf:E0Nf));
535 splx(s);
536 return 1;
537 }
538
539 enum {
540 /* UART control */
541 Cpc0Ucr= 0xF5, /* UART control register */
542
543 U0Dc= 1<<21, /* UART0 DMA clear enable */
544 U0Dt= 1<<20, /* enable UART0 DMA transmit channel */
545 U0Dr= 1<<19, /* enable UART0 DMA receive channel */
546 U1Dc= 1<<18, /* UART1 DMA clear enable */
547 U1Dt= 1<<17, /* enable UART1 DMA transmit channel */
548 U1Dr= 1<<16, /* enable UART1 DMA receive channel */
549 U1Div_s= 8, /* UART1 serial clock divisor (shift) */
550 U1Stop= 1<<8,
551 U0Div_s= 0, /* UART0 serial clock divisor (shift) */
552 U0Stop= 1<<0,
553 UDiv_m= 0x7F, /* UARTx divisor mask */
554 };
555
556 static ulong
findserialclock(int rate,ulong * freq)557 findserialclock(int rate, ulong *freq)
558 {
559 ulong d, b;
560 ulong serialclock;
561 int actual, e, beste, bestd;
562
563 *freq = 0;
564 if(rate == 0)
565 return 0;
566 d = ((m->pllhz+m->opbhz-1)/m->opbhz)*2; /* double to allow for later rounding */
567 beste = 0;
568 bestd = -1;
569 for(; d<=128; d++){
570 serialclock = (2*m->pllhz)/d;
571 b = ((serialclock+8*rate-1)/(rate*16))>>1;
572 actual = ((serialclock+8*b-1)/(b*16))>>1;
573 e = rate-actual;
574 if(e < 0)
575 e = -e;
576 if(bestd < 0 || e < beste || e == beste && (bestd&1) && (d&1)==0){
577 beste = e;
578 bestd = d;
579 }
580 }
581 if(bestd > 0)
582 *freq = m->pllhz/bestd;
583 return bestd;
584 }
585
586 /*
587 * return a value for UARTn's baud rate generator, and
588 * set a corresponding divsor in the UARTn clock generator
589 * (between 2 and 128)
590 */
591 ulong
archuartclock(int n,int rate)592 archuartclock(int n, int rate)
593 {
594 int d, s;
595 ulong m, freq;
596
597 d = findserialclock(rate, &freq);
598 if(d <= 0)
599 d = U0Stop;
600 m = UDiv_m;
601 if(n){
602 d <<= U1Div_s;
603 m <<= U1Div_s;
604 }
605 s = splhi();
606 putdcr(Cpc0Ucr, (getdcr(Cpc0Ucr) & ~m) | d);
607 splx(s);
608 return freq;
609 }
610
611 void
archuartdma(int n,int on)612 archuartdma(int n, int on)
613 {
614 ulong r;
615 int s;
616
617 r = n? (U1Dc|U1Dt|U1Dr): (U0Dc|U0Dt|U0Dr);
618 if(on){
619 s = splhi();
620 putdcr(Cpc0Ucr, getdcr(Cpc0Ucr) | r);
621 splx(s);
622 }else{
623 s = splhi();
624 putdcr(Cpc0Ucr, getdcr(Cpc0Ucr) & ~r);
625 splx(s);
626 }
627 }
628
629 /*
630 * boot environment in eeprom
631 */
632
633 enum {
634 EEpromHdr= 8, /* bytes */
635 Envsize= 0x400,
636 };
637
638 static I2Cdev eedev;
639 static struct {
640 uchar buf[Envsize];
641 int size;
642 } bootenv;
643
644 static int
eepromitem(uchar * buf,int lim,ulong * off)645 eepromitem(uchar *buf, int lim, ulong *off)
646 {
647 int l;
648 uchar b;
649
650 if(i2crecv(&eedev, &b, 1, (*off)++) != 1)
651 return -1;
652 l = b;
653 if(l & 0x80){
654 if(i2crecv(&eedev, &b, 1, (*off)++) != 1)
655 return -1;
656 l = ((l & 0x7F)<<8) | b;
657 }
658 if(buf == nil)
659 return l;
660 if(l > lim)
661 l = lim;
662 return i2crecv(&eedev, buf, l, *off);
663 }
664
665 void
eepromscan(void)666 eepromscan(void)
667 {
668 int n, l;
669 ulong off;
670 uchar buf[2];
671 char *p, *ep, *v;
672
673 eedev.addr = 0x50;
674 eedev.salen = 2;
675 i2csetup(1);
676 n = i2crecv(&eedev, buf, sizeof(buf), 0);
677 if(n <= 0){
678 iprint("eepromscan: %d\n", n);
679 return;
680 }
681 if(buf[0] != 0xEF || buf[1] != 0xBE){
682 iprint("eeprom invalid\n");
683 return;
684 }
685 bootenv.size = 0;
686 for(off = EEpromHdr; off < 16384;){
687 l = eepromitem(bootenv.buf, sizeof(bootenv.buf), &off); /* key */
688 if(l <= 0)
689 break;
690 off += l;
691 if(l == 7 && memcmp(bootenv.buf, "PPCBOOT", 7) == 0){ /* intrinsyc key */
692 bootenv.size = eepromitem(bootenv.buf, sizeof(bootenv.buf), &off);
693 break;
694 }
695 l = eepromitem(nil, 0, &off); /* skip value */
696 if(l < 0)
697 break;
698 off += l+2; /* 2 byte crc */
699 }
700 p = (char*)bootenv.buf+4; /* skip crc */
701 ep = p+bootenv.size;
702 for(; p < ep && *p; p += l){
703 l = strlen(p)+1;
704 v = strchr(p, '=');
705 if(v != nil)
706 *v++ = 0;
707 else
708 v = "";
709 addconf(p, v);
710 if(0)
711 iprint("%q = %q\n", p, v);
712 }
713 }
714
715 ulong
logfsnow(void)716 logfsnow(void)
717 {
718 return rtctime();
719 }
720