new format for stray unibus intr printf
[unix-history] / usr / src / sys / vax / vax / machdep.c
CommitLineData
dca3793c 1/* machdep.c 4.21 81/03/03 */
79821b2c
BJ
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/dir.h"
6#include "../h/user.h"
7#include "../h/map.h"
8#include "../h/reg.h"
9#include "../h/mtpr.h"
10#include "../h/clock.h"
11#include "../h/pte.h"
12#include "../h/vm.h"
13#include "../h/proc.h"
14#include "../h/psl.h"
8ae22d0f 15#include "../h/buf.h"
f5eeaba8 16#include "../h/uba.h"
0dc06be8
BJ
17#include "../h/cons.h"
18#include "../h/reboot.h"
2de46def 19#include "../h/conf.h"
8ae22d0f
BJ
20#include "../h/mem.h"
21#include "../h/cpu.h"
c34926db
BJ
22#include "../h/inode.h"
23#include "../h/file.h"
24#include "../h/text.h"
25#include "../h/clist.h"
26#include "../h/callout.h"
27#include "../h/cmap.h"
2de46def 28#include <frame.h>
79821b2c 29
2de46def
BJ
30int coresw = 0;
31int printsw = 0;
32
dca3793c 33char version[] = "VM/UNIX (Berkeley Version 4.21) 81/03/03 11:04:57 \n";
79821b2c
BJ
34int icode[] =
35{
48575cec
BJ
36 0x9f19af9f, /* pushab [&"init",0]; pushab */
37 0x02dd09af, /* "/etc/init"; pushl $2 */
79821b2c
BJ
38 0xbc5c5ed0, /* movl sp,ap; chmk */
39 0x2ffe110b, /* $exec; brb .; "/ */
40 0x2f637465, /* etc/ */
0dc06be8
BJ
41 0x74696e69, /* init" */
42 0x00000000, /* \0\0\0"; 0 */
79821b2c
BJ
43 0x00000014, /* [&"init", */
44 0x00000000, /* 0] */
45};
46int szicode = sizeof(icode);
79821b2c
BJ
47
48/*
49 * Machine-dependent startup code
50 */
51startup(firstaddr)
c34926db 52 int firstaddr;
79821b2c
BJ
53{
54 register int unixsize;
a53ab6ba
BJ
55 register int i;
56 register struct pte *pte;
c34926db 57 register caddr_t v;
79821b2c 58
90f8d91f
BJ
59 /*
60 * Initialize error message buffer (at end of core).
61 */
62 maxmem -= CLSIZE;
63 pte = msgbufmap;
64 for (i = 0; i < CLSIZE; i++)
65 *(int *)pte++ = PG_V | PG_KW | (maxmem + i);
66 mtpr(TBIA, 1);
67
79821b2c
BJ
68 /*
69 * Good {morning,afternoon,evening,night}.
70 */
90f8d91f
BJ
71 printf(version);
72 printf("real mem = %d\n", ctob(maxmem));
cf19cacc 73
79821b2c 74 /*
c34926db
BJ
75 * First determine how many buffers are reasonable.
76 * Current alg is 32 per megabyte, with min of 32.
77 * We allocate 1/2 as many swap buffer headers as file i/o buffers.
79821b2c 78 */
c34926db 79 nbuf = (32 * physmem) / btoc(1024*1024); if (nbuf < 32) nbuf = 32;
0a34b6fd 80 nswbuf = (nbuf / 2) &~ 1; /* force even */
a53ab6ba
BJ
81
82 /*
c34926db 83 * Allocate space for system data structures.
a53ab6ba 84 */
c34926db
BJ
85 v = (caddr_t)(0x80000000 | (firstaddr * NBPG));
86#define valloc(name, type, num) \
87 (name) = (type *)(v); (v) = (caddr_t)((name)+(num))
88#define valloclim(name, type, num, lim) \
89 (name) = (type *)(v); (v) = (caddr_t)((lim) = ((name)+(num)))
90 valloc(buffers, char, BSIZE*nbuf);
91 valloc(buf, struct buf, nbuf);
92 valloc(swbuf, struct buf, nswbuf);
0a34b6fd
BJ
93 valloc(swsize, short, nswbuf); /* note: nswbuf is even */
94 valloc(swpf, int, nswbuf);
c34926db
BJ
95 valloclim(inode, struct inode, ninode, inodeNINODE);
96 valloclim(file, struct file, nfile, fileNFILE);
97 valloclim(proc, struct proc, nproc, procNPROC);
98 valloclim(text, struct text, ntext, textNTEXT);
99 valloc(cfree, struct cblock, nclist);
100 valloc(callout, struct callout, ncallout);
233328fc
BJ
101 valloc(swapmap, struct map, nswapmap = nproc * 2);
102 valloc(argmap, struct map, ARGMAPSIZE);
c34926db
BJ
103 valloc(kernelmap, struct map, nproc);
104
105 /*
106 * Now allocate space for core map
107 */
108 ncmap = (physmem*NBPG - ((int)v &~ 0x80000000)) /
109 (NBPG*CLSIZE + sizeof (struct cmap));
110 valloclim(cmap, struct cmap, ncmap, ecmap);
111
112 /*
113 * Clear allocated space, and make r/w entries
114 * for the space in the kernel map.
115 */
0a34b6fd 116 unixsize = btoc((int)ecmap &~ 0x80000000);
c34926db
BJ
117 if (unixsize >= physmem - 8*UPAGES)
118 panic("no memory");
119 pte = &Sysmap[firstaddr];
120 for (i = firstaddr; i < unixsize; i++) {
121 *(int *)(&Sysmap[i]) = PG_V | PG_KW | i;
122 clearseg(i);
123 }
a53ab6ba 124 mtpr(TBIA, 1);
79821b2c
BJ
125
126 /*
233328fc
BJ
127 * Initialize memory allocator and swap
128 * and user page table maps.
129 *
130 * THE USER PAGE TABLE MAP IS CALLED ``kernelmap''
131 * WHICH IS A VERY UNDESCRIPTIVE AND INCONSISTENT NAME.
79821b2c
BJ
132 */
133 meminit(unixsize, maxmem);
a53ab6ba 134 maxmem = freemem;
79821b2c 135 printf("avail mem = %d\n", ctob(maxmem));
233328fc 136 rminit(kernelmap, USRPTSIZE, 1, "usrpt", nproc);
cf19cacc
BJ
137
138 /*
139 * Configure the system.
140 */
141 configure();
142
143 /*
144 * Clear restart inhibit flags.
145 */
146 tocons(TXDB_CWSI);
147 tocons(TXDB_CCSI);
79821b2c
BJ
148}
149
150/*
151 * set up a physical address
152 * into users virtual address space.
153 */
154sysphys()
155{
156
157 if(!suser())
158 return;
159 u.u_error = EINVAL;
160}
161
162/*
b559a38a
BJ
163 * Initialze the clock, based on the time base which is, e.g.
164 * from a filesystem. Base provides the time to within six months,
165 * and the time of year clock provides the rest.
79821b2c 166 */
354a4341 167clkinit(base)
b559a38a 168 time_t base;
354a4341 169{
b559a38a 170 register unsigned todr = mfpr(TODR);
890f1888 171 long deltat;
b559a38a
BJ
172 int year = YRREF;
173
f4d57f63 174 if (base < 5*SECYR) {
e506b649 175 printf("WARNING: preposterous time in file system");
aa94c536 176 time = 6*SECYR + 186*SECDAY + SECDAY/2;
cdc19302
BJ
177 clkset();
178 goto check;
f4d57f63 179 }
b559a38a
BJ
180 /*
181 * Have been told that VMS keeps time internally with base TODRZERO.
182 * If this is correct, then this routine and VMS should maintain
183 * the same date, and switching shouldn't be painful.
2de46def
BJ
184 * (Unfortunately, VMS keeps local time, so when you run UNIX
185 * and VMS, VMS runs on GMT...).
b559a38a
BJ
186 */
187 if (todr < TODRZERO) {
188 printf("WARNING: todr too small (battery backup failed?)");
189 time = base;
190 /*
191 * Believe the time in the file system for lack of
192 * anything better, resetting the TODR.
193 */
194 clkset();
195 goto check;
196 }
197 /*
198 * Sneak to within 6 month of the time in the filesystem,
199 * by starting with the time of the year suggested by the TODR,
200 * and advancing through succesive years. Adding the number of
201 * seconds in the current year takes us to the end of the current year
202 * and then around into the next year to the same position.
203 */
204 for (time = (todr-TODRZERO)/100; time < base-SECYR/2; time += SECYR) {
205 if (LEAPYEAR(year))
206 time += SECDAY;
207 year++;
208 }
354a4341 209
b559a38a
BJ
210 /*
211 * See if we gained/lost two or more days;
212 * if so, assume something is amiss.
213 */
890f1888
BJ
214 deltat = time - base;
215 if (deltat < 0)
216 deltat = -deltat;
b559a38a
BJ
217 if (deltat < 2*SECDAY)
218 return;
219 printf("WARNING: clock %s %d days",
220 time < base ? "lost" : "gained", deltat / SECDAY);
221check:
222 printf(" -- CHECK AND RESET THE DATE!\n");
354a4341
BJ
223}
224
b559a38a
BJ
225/*
226 * Reset the TODR based on the time value; used when the TODR
227 * has a preposterous value and also when the time is reset
228 * by the stime system call. Also called when the TODR goes past
229 * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
230 * to wrap the TODR around.
231 */
354a4341
BJ
232clkset()
233{
b559a38a
BJ
234 int year = YRREF;
235 unsigned secyr;
236 unsigned yrtime = time;
354a4341 237
b559a38a
BJ
238 /*
239 * Whittle the time down to an offset in the current year,
240 * by subtracting off whole years as long as possible.
241 */
242 for (;;) {
243 secyr = SECYR;
244 if (LEAPYEAR(year))
245 secyr += SECDAY;
246 if (yrtime < secyr)
247 break;
248 yrtime -= secyr;
249 year++;
250 }
251 mtpr(TODR, TODRZERO + yrtime*100);
354a4341
BJ
252}
253
79821b2c
BJ
254#ifdef PGINPROF
255/*
256 * Return the difference (in microseconds)
257 * between the current time and a previous
258 * time as represented by the arguments.
259 * If there is a pending clock interrupt
260 * which has not been serviced due to high
261 * ipl, return error code.
262 */
263vmtime(otime, olbolt, oicr)
264 register int otime, olbolt, oicr;
265{
266
267 if (mfpr(ICCS)&ICCS_INT)
268 return(-1);
269 else
270 return(((time-otime)*60 + lbolt-olbolt)*16667 + mfpr(ICR)-oicr);
271}
272#endif
273
274/*
275 * Send an interrupt to process
f815f998
BJ
276 *
277 * SHOULD CHANGE THIS TO PASS ONE MORE WORK SO THAT ALL INFORMATION
278 * PROVIDED BY HARDWARE IS AVAILABLE TO THE USER PROCESS.
79821b2c
BJ
279 */
280sendsig(p, n)
858ecf0f 281 int (*p)();
79821b2c
BJ
282{
283 register int *usp, *regs;
284
285 regs = u.u_ar0;
286 usp = (int *)regs[SP];
79821b2c
BJ
287 usp -= 5;
288 if ((int)usp <= USRSTACK - ctob(u.u_ssize))
81263dba 289 (void) grow((unsigned)usp);
79821b2c 290 ; /* Avoid asm() label botch */
858ecf0f 291#ifndef lint
79821b2c
BJ
292 asm("probew $3,$20,(r11)");
293 asm("beql bad");
858ecf0f
BJ
294#else
295 if (useracc((caddr_t)usp, 0x20, 1))
296 goto bad;
297#endif
79821b2c 298 *usp++ = n;
dca3793c
BJ
299 if (n == SIGILL || n == SIGFPE) {
300 *usp++ = u.u_code;
301 u.u_code = 0;
302 } else
303 *usp++ = 0;
858ecf0f 304 *usp++ = (int)p;
79821b2c
BJ
305 *usp++ = regs[PC];
306 *usp++ = regs[PS];
307 regs[SP] = (int)(usp - 5);
79821b2c
BJ
308 regs[PS] &= ~(PSL_CM|PSL_FPD);
309 regs[PC] = (int)u.u_pcb.pcb_sigc;
310 return;
311
79821b2c 312asm("bad:");
79821b2c 313bad:
2e2312a9 314 psignal(u.u_procp, SIGKILL);
79821b2c
BJ
315}
316
9a3561c2
BJ
317dorti()
318{
2de46def 319 struct frame frame;
9a3561c2
BJ
320 register int sp;
321 register int reg, mask;
322 extern int ipcreg[];
9a3561c2
BJ
323
324 (void) copyin((caddr_t)u.u_ar0[FP], (caddr_t)&frame, sizeof (frame));
325 sp = u.u_ar0[FP] + sizeof (frame);
2de46def
BJ
326 u.u_ar0[PC] = frame.fr_savpc;
327 u.u_ar0[FP] = frame.fr_savfp;
328 u.u_ar0[AP] = frame.fr_savap;
329 mask = frame.fr_mask;
9a3561c2
BJ
330 for (reg = 0; reg <= 11; reg++) {
331 if (mask&1) {
858ecf0f 332 u.u_ar0[ipcreg[reg]] = fuword((caddr_t)sp);
9a3561c2
BJ
333 sp += 4;
334 }
335 mask >>= 1;
336 }
2de46def
BJ
337 sp += frame.fr_spa;
338 u.u_ar0[PS] = (u.u_ar0[PS] & 0xffff0000) | frame.fr_psw;
339 if (frame.fr_s)
858ecf0f 340 sp += 4 + 4 * (fuword((caddr_t)sp) & 0xff);
9a3561c2 341 /* phew, now the rei */
858ecf0f 342 u.u_ar0[PC] = fuword((caddr_t)sp);
9a3561c2 343 sp += 4;
858ecf0f 344 u.u_ar0[PS] = fuword((caddr_t)sp);
9a3561c2
BJ
345 sp += 4;
346 u.u_ar0[PS] |= PSL_CURMOD|PSL_PRVMOD;
347 u.u_ar0[PS] &= ~PSL_USERCLR;
cdc19302 348 u.u_ar0[SP] = (int)sp;
9a3561c2
BJ
349}
350
79821b2c 351/*
dca3793c
BJ
352 * Memenable enables the memory controlle corrected data reporting.
353 * This runs at regular intervals, turning on the interrupt.
354 * The interrupt is turned off, per memory controller, when error
355 * reporting occurs. Thus we report at most once per memintvl.
79821b2c 356 */
79821b2c
BJ
357int memintvl = MEMINTVL;
358
dca3793c 359memenable()
79821b2c 360{
8ae22d0f
BJ
361 register struct mcr *mcr;
362 register int m;
d96afe11 363
8ae22d0f
BJ
364 for (m = 0; m < nmcr; m++) {
365 mcr = mcraddr[m];
366 switch (cpu) {
367#if VAX780
368 case VAX_780:
dca3793c 369 M780_ENA(mcr);
8ae22d0f 370 break;
48575cec 371#endif
8ae22d0f
BJ
372#if VAX750
373 case VAX_750:
dca3793c 374 M750_ENA(mcr);
8ae22d0f 375 break;
48575cec 376#endif
8ae22d0f 377 }
dca3793c
BJ
378 }
379 if (memintvl > 0)
380 timeout(memenable, (caddr_t)0, memintvl);
381}
382
383/*
384 * Memerr is the interrupt routine for corrected read data
385 * interrupts. It looks to see which memory controllers have
386 * unreported errors, reports them, and disables further
387 * reporting for a time on those controller.
388 */
389memerr()
390{
391 register struct mcr *mcr;
392 register int m;
393
394 for (m = 0; m < nmcr; m++) {
395 mcr = mcraddr[m];
8ae22d0f
BJ
396 switch (cpu) {
397#if VAX780
398 case VAX_780:
dca3793c
BJ
399 if (M780_ERR(mcr)) {
400 printf("memerr mcr%d addr %x syn %x\n",
401 m, M780_ADDR(mcr), M780_SYN(mcr));
402 M780_INH(mcr);
403 }
8ae22d0f 404 break;
d96afe11 405#endif
8ae22d0f
BJ
406#if VAX750
407 case VAX_750:
dca3793c
BJ
408 if (M750_ERR(mcr)) {
409 printf("memerr mcr%d addr %x syn %x\n",
410 m, M750_ADDR(mcr), M750_SYN(mcr));
411 M750_INH(mcr);
412 }
8ae22d0f
BJ
413 break;
414#endif
415 }
416 }
79821b2c
BJ
417}
418
419/*
420 * Invalidate single all pte's in a cluster
421 */
422tbiscl(v)
423 unsigned v;
424{
425 register caddr_t addr; /* must be first reg var */
426 register int i;
427
428 asm(".set TBIS,58");
429 addr = ptob(v);
430 for (i = 0; i < CLSIZE; i++) {
431#ifdef lint
432 mtpr(TBIS, addr);
433#else
434 asm("mtpr r11,$TBIS");
435#endif
436 addr += NBPG;
437 }
438}
b559a38a 439
0dc06be8
BJ
440int waittime = -1;
441
442boot(panic, arghowto)
443 int panic, arghowto;
444{
445 register int howto; /* r11 == how to boot */
446 register int devtype; /* r10 == major of root dev */
447
448 howto = arghowto;
cf19cacc 449 if ((howto&RB_NOSYNC)==0 && waittime < 0 && bfreelist[0].b_forw) {
0dc06be8
BJ
450 waittime = 0;
451 update();
87771f34
BJ
452 printf("syncing disks... ");
453 while (++waittime <= 5)
0dc06be8 454 sleep((caddr_t)&lbolt, PZERO);
87771f34 455 printf("done\n");
0dc06be8
BJ
456 }
457 splx(0x1f); /* extreme priority */
458 devtype = major(rootdev);
2de46def
BJ
459 if (howto&RB_HALT) {
460 printf("halting (in tight loop); hit\n\t^P\n\tHALT\n\n");
461 mtpr(IPL, 0x1f);
462 for (;;)
463 ;
464 } else {
465 if (panic == RB_PANIC)
466 doadump();
48575cec 467 tocons(TXDB_BOOT);
2de46def 468 }
e5a79c70
BJ
469#if VAX750
470 if (cpu == VAX_750)
471 { asm("movl r11,r5"); } /* boot flags go in r5 */
48575cec 472#endif
0dc06be8
BJ
473 for (;;)
474 asm("halt");
858ecf0f
BJ
475#ifdef lint
476 printf("howto %d, devtype %d\n", howto, devtype);
477#endif
478 /*NOTREACHED*/
479}
480
481tocons(c)
482{
483
484 while ((mfpr(TXCS)&TXCS_RDY) == 0)
485 continue;
486 mtpr(TXDB, c);
0dc06be8 487}
2de46def
BJ
488
489/*
490 * Doadump comes here after turning off memory management and
491 * getting on the dump stack, either when called above, or by
492 * the auto-restart code.
493 */
494dumpsys()
495{
496
497 if ((minor(dumpdev)&07) != 1)
498 return;
499 printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
dca3793c
BJ
500 printf("dump ");
501 switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {
502
503 case ENXIO:
504 printf("device bad\n");
505 break;
506
507 case EFAULT:
508 printf("device not ready\n");
509 break;
510
511 case EINVAL:
512 printf("area improper\n");
513 break;
514
515 case EIO:
516 printf("i/o error");
517 break;
518
519 default:
520 printf("succeeded");
521 break;
522 }
2de46def 523}
a58c4eb5 524
dca3793c
BJ
525/*
526 * Machine check error recovery code.
527 * Print out the machine check frame and then give up.
528 */
a58c4eb5
BJ
529char *mc780[] = {
530 "cp read", "ctrl str par", "cp tbuf par", "cp cache par",
531 "cp rdtimo", "cp rds", "ucode lost", 0,
532 0, 0, "ib tbuf par", 0,
533 "ib rds", "ib rd timo", 0, "ib cache par"
534};
535
dca3793c
BJ
536/*
537 * Frame for a 780
538 */
a58c4eb5 539struct mc780frame {
dca3793c
BJ
540 int mc8_bcnt; /* byte count == 28 */
541 int mc8_summary; /* summary parameter (as above) */
542 int mc8_cpues; /* cpu error status */
543 int mc8_upc; /* micro pc */
544 int mc8_vaviba; /* va/viba register */
545 int mc8_dreg; /* d register */
546 int mc8_tber0; /* tbuf error reg 0 */
547 int mc8_tber1; /* tbuf error reg 1 */
548 int mc8_timo; /* timeout address divided by 4 */
549 int mc8_parity; /* parity */
550 int mc8_sbier; /* sbi error register */
551 int mc8_pc; /* trapped pc */
552 int mc8_psl; /* trapped psl */
a78738a8
BJ
553};
554struct mc750frame {
dca3793c
BJ
555 int mc5_bcnt; /* byte count == 28 */
556 int mc5_summary; /* summary parameter (as above) */
557 int mc5_va; /* virtual address register */
558 int mc5_errpc; /* error pc */
a78738a8 559 int mc5_mdr;
dca3793c
BJ
560 int mc5_svmode; /* saved mode register */
561 int mc5_rdtimo; /* read lock timeout */
562 int mc5_tbgpar; /* tb group parity error register */
563 int mc5_cacherr; /* cache error register */
564 int mc5_buserr; /* bus error register */
565 int mc5_mcesr; /* machine check status register */
566 int mc5_pc; /* trapped pc */
567 int mc5_psl; /* trapped psl */
a58c4eb5
BJ
568};
569
a78738a8
BJ
570machinecheck(cmcf)
571 caddr_t cmcf;
a58c4eb5 572{
a78738a8 573 register int type = ((struct mc780frame *)cmcf)->mc8_summary;
a58c4eb5
BJ
574
575 printf("machine check %x: %s%s\n", type, mc780[type&0xf],
576 (type&0xf0) ? " abort" : " fault");
a78738a8
BJ
577 switch (cpu) {
578#if VAX780
579 case VAX_780: {
580 register struct mc780frame *mcf = (struct mc780frame *)cmcf;
581 register int sbifs;
582 printf("\tcpues %x upc %x va/viba %x dreg %x tber %x %x\n",
583 mcf->mc8_cpues, mcf->mc8_upc, mcf->mc8_vaviba,
584 mcf->mc8_dreg, mcf->mc8_tber0, mcf->mc8_tber1);
585 sbifs = mfpr(SBIFS);
586 printf("\ttimo %x parity %x sbier %x pc %x psl %x sbifs %x\n",
587 mcf->mc8_timo*4, mcf->mc8_parity, mcf->mc8_sbier,
588 mcf->mc8_pc, mcf->mc8_psl, sbifs);
589 /* THE FUNNY BITS IN THE FOLLOWING ARE FROM THE ``BLACK */
590 /* BOOK AND SHOULD BE PUT IN AN ``sbi.h'' */
591 mtpr(SBIFS, sbifs &~ 0x2000000);
592 mtpr(SBIER, mfpr(SBIER) | 0x70c0);
593 break;
594 }
595#endif
596#if VAX750
597 case VAX_750: {
598 register struct mc750frame *mcf = (struct mc750frame *)cmcf;
599 printf("\tva %x errpc %x mdr %x smr %x tbgpar %x cacherr %x\n",
600 mcf->mc5_va, mcf->mc5_errpc, mcf->mc5_mdr, mcf->mc5_svmode,
601 mcf->mc5_rdtimo, mcf->mc5_tbgpar, mcf->mc5_cacherr);
602 printf("\tbuserr %x mcesr %x pc %x psl %x mcsr %x\n",
603 mcf->mc5_buserr, mcf->mc5_mcesr, mcf->mc5_pc, mcf->mc5_psl,
604 mfpr(MCSR));
605 mtpr(MCESR, 0xf);
606 break;
607 }
608#endif
609 }
a58c4eb5
BJ
610 panic("mchk");
611}