836780d75dc73af69d10fb3a905794622bd36dda
/* machdep.c 4.61 82/09/04 */
#include "../vax/clock.h"
#include "../h/callout.h"
0x9f19af9f, /* pushab [&"init",0]; pushab */
0x02dd09af, /* "/etc/init"; pushl $2 */
0xbc5c5ed0, /* movl sp,ap; chmk */
0x2ffe110b, /* $exec; brb .; "/ */
0x00000000, /* \0\0\0"; 0 */
0x00000014, /* [&"init", */
int szicode
= sizeof(icode
);
0x9f19af9f, /* pushab [&"mush",0]; pushab */
0x02dd09af, /* "/etc/mush"; pushl $2 */
0xbc5c5ed0, /* movl sp,ap; chmk */
0x2f01bc0b, /* $exec; chmk $exit; "/ */
0x00000000, /* \0\0\0"; 0 */
0x00000014, /* [&"mush", */
int szmcode
= sizeof(mcode
);
* Declare these as initialized data so we can patch them.
* Machine-dependent startup code
register struct pte
*pte
;
* Initialize error message buffer (at end of core).
maxmem
-= btoc(sizeof (struct msgbuf
));
for (i
= 0; i
< btoc(sizeof (struct msgbuf
)); i
++)
*(int *)pte
++ = PG_V
| PG_KW
| (maxmem
+ i
);
* Good {morning,afternoon,evening,night}.
printf("real mem = %d\n", ctob(maxmem
));
* First determine how many buffers are reasonable.
* Current alg is 16 per megabyte, with min of 16.
* We allocate 1/2 as many swap buffer headers as file i/o buffers.
nbuf
= (16 * physmem
) / btoc(1024*1024);
nswbuf
= (nbuf
/ 2) &~ 1; /* force even */
nswbuf
= 256; /* sanity */
* Allocate space for system data structures.
v
= (caddr_t
)(0x80000000 | (firstaddr
* NBPG
));
#define valloc(name, type, num) \
(name) = (type *)(v); (v) = (caddr_t)((name)+(num))
#define valloclim(name, type, num, lim) \
(name) = (type *)(v); (v) = (caddr_t)((lim) = ((name)+(num)))
valloc(buffers
, char, MAXBSIZE
* nbuf
);
valloc(buf
, struct buf
, nbuf
);
valloc(swbuf
, struct buf
, nswbuf
);
valloc(swsize
, short, nswbuf
); /* note: nswbuf is even */
valloc(swpf
, int, nswbuf
);
valloclim(inode
, struct inode
, ninode
, inodeNINODE
);
valloclim(file
, struct file
, nfile
, fileNFILE
);
valloclim(proc
, struct proc
, nproc
, procNPROC
);
valloclim(text
, struct text
, ntext
, textNTEXT
);
valloc(cfree
, struct cblock
, nclist
);
valloc(callout
, struct callout
, ncallout
);
valloc(swapmap
, struct map
, nswapmap
= nproc
* 2);
valloc(argmap
, struct map
, ARGMAPSIZE
);
valloc(kernelmap
, struct map
, nproc
);
valloc(mbmap
, struct map
, nmbclusters
/4);
valloclim(quota
, struct quota
, nquota
, quotaNQUOTA
);
valloclim(dquot
, struct dquot
, ndquot
, dquotNDQUOT
);
* Now allocate space for core map
ncmap
= (physmem
*NBPG
- ((int)v
&~ 0x80000000)) /
(NBPG
*CLSIZE
+ sizeof (struct cmap
));
valloclim(cmap
, struct cmap
, ncmap
, ecmap
);
if ((((int)(ecmap
+1))&~0x80000000) > SYSPTSIZE
*NBPG
)
panic("sys pt too small");
* Clear allocated space, and make r/w entries
* for the space in the kernel map.
unixsize
= btoc((int)(ecmap
+1) &~ 0x80000000);
if (unixsize
>= physmem
- 8*UPAGES
)
pte
= &Sysmap
[firstaddr
];
for (i
= firstaddr
; i
< unixsize
; i
++) {
*(int *)(&Sysmap
[i
]) = PG_V
| PG_KW
| i
;
for (i
= 1; i
< ncallout
; i
++)
callout
[i
-1].c_next
= &callout
[i
];
* Initialize memory allocator and swap
* and user page table maps.
* THE USER PAGE TABLE MAP IS CALLED ``kernelmap''
* WHICH IS A VERY UNDESCRIPTIVE AND INCONSISTENT NAME.
meminit(unixsize
, maxmem
);
printf("avail mem = %d\n", ctob(maxmem
));
rminit(kernelmap
, USRPTSIZE
, 1, "usrpt", nproc
);
rminit(mbmap
, (nmbclusters
- 1) * CLSIZE
, CLSIZE
, "mbclusters",
* Clear restart inhibit flags.
* set up a physical address
* into users virtual address space.
* Initialze the clock, based on the time base which is, e.g.
* from a filesystem. Base provides the time to within six months,
* and the time of year clock provides the rest.
register unsigned todr
= mfpr(TODR
);
printf("WARNING: preposterous time in file system");
time
.tv_sec
= 6*SECYR
+ 186*SECDAY
+ SECDAY
/2;
* Have been told that VMS keeps time internally with base TODRZERO.
* If this is correct, then this routine and VMS should maintain
* the same date, and switching shouldn't be painful.
* We must correct for the fact that VMS keeps local time
printf("WARNING: todr too small");
* Believe the time in the file system for lack of
* anything better, resetting the TODR.
* Sneak to within 6 month of the time in the filesystem,
* by starting with the time of the year suggested by the TODR,
* and advancing through succesive years. Adding the number of
* seconds in the current year takes us to the end of the current year
* and then around into the next year to the same position.
time
.tv_sec
= (todr
-TODRZERO
)/100 + timezone
*60;
while (time
.tv_sec
< base
-SECYR
/2) {
* See if we gained/lost two or more days;
* if so, assume something is amiss.
deltat
= time
.tv_sec
- base
;
printf("WARNING: clock %s %d days",
time
.tv_sec
< base
? "lost" : "gained", deltat
/ SECDAY
);
printf(" -- CHECK AND RESET THE DATE!\n");
* Reset the TODR based on the time value; used when the TODR
* has a preposterous value and also when the time is reset
* by the stime system call. Also called when the TODR goes past
* TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
* to wrap the TODR around.
unsigned yrtime
= time
.tv_sec
- timezone
*60;
* Whittle the time down to an offset in the current year,
* by subtracting off whole years as long as possible.
mtpr(TODR
, TODRZERO
+ yrtime
*100);
* Return the difference (in microseconds)
* between the current time and a previous
* time as represented by the arguments.
* If there is a pending clock interrupt
* which has not been serviced due to high
* ipl, return error code.
vmtime(otime
, olbolt
, oicr
)
register int otime
, olbolt
, oicr
;
return(((time
.tv_sec
-otime
)*60 + lbolt
-olbolt
)*16667 + mfpr(ICR
)-oicr
);
* Send an interrupt to process
* SHOULD CHANGE THIS TO PASS ONE MORE WORD SO THAT ALL INFORMATION
* PROVIDED BY HARDWARE IS AVAILABLE TO THE USER PROCESS.
register int *usp
, *regs
;
if ((int)usp
<= USRSTACK
- ctob(u
.u_ssize
))
(void) grow((unsigned)usp
);
; /* Avoid asm() label botch */
asm("probew $3,$20,(r11)");
if (useracc((caddr_t
)usp
, 0x20, 1))
if (n
== SIGILL
|| n
== SIGFPE
) {
regs
[SP
] = (int)(usp
- 5);
regs
[PS
] &= ~(PSL_CM
|PSL_FPD
);
regs
[PC
] = (int)u
.u_pcb
.pcb_sigc
;
* Process has trashed its stack; give it an illegal
* instruction to halt it in its tracks.
u
.u_signal
[SIGILL
] = SIG_DFL
;
u
.u_procp
->p_siga0
&= ~(1<<(SIGILL
-1));
u
.u_procp
->p_siga1
&= ~(1<<(SIGILL
-1));
psignal(u
.u_procp
, SIGILL
);
(void) copyin((caddr_t
)u
.u_ar0
[FP
], (caddr_t
)&frame
, sizeof (frame
));
sp
= u
.u_ar0
[FP
] + sizeof (frame
);
u
.u_ar0
[PC
] = frame
.fr_savpc
;
u
.u_ar0
[FP
] = frame
.fr_savfp
;
u
.u_ar0
[AP
] = frame
.fr_savap
;
for (reg
= 0; reg
<= 11; reg
++) {
u
.u_ar0
[ipcreg
[reg
]] = fuword((caddr_t
)sp
);
u
.u_ar0
[PS
] = (u
.u_ar0
[PS
] & 0xffff0000) | frame
.fr_psw
;
sp
+= 4 + 4 * (fuword((caddr_t
)sp
) & 0xff);
u
.u_ar0
[PC
] = fuword((caddr_t
)sp
);
u
.u_ar0
[PS
] = fuword((caddr_t
)sp
);
u
.u_ar0
[PS
] |= PSL_USERSET
;
u
.u_ar0
[PS
] &= ~PSL_USERCLR
;
* Memenable enables the memory controlle corrected data reporting.
* This runs at regular intervals, turning on the interrupt.
* The interrupt is turned off, per memory controller, when error
* reporting occurs. Thus we report at most once per memintvl.
register struct mcr
*mcr
;
for (m
= 0; m
< nmcr
; m
++) {
timeout(memenable
, (caddr_t
)0, memintvl
);
* Memerr is the interrupt routine for corrected read data
* interrupts. It looks to see which memory controllers have
* unreported errors, reports them, and disables further
* reporting for a time on those controller.
register struct mcr
*mcr
;
for (m
= 0; m
< nmcr
; m
++) {
printf("mcr%d: soft ecc addr %x syn %x\n",
m
, M780_ADDR(mcr
), M780_SYN(mcr
));
printf("mcr%d: soft ecc addr %x syn %x\n",
m
, M750_ADDR(mcr
), M750_SYN(mcr
));
amcr
.mc_reg
[0] = mcr
->mc_reg
[0];
printf("mcr%d: soft ecc addr %x syn %x\n",
m
, M730_ADDR(&amcr
), M730_SYN(&amcr
));
* Figure out what chip to replace on Trendata boards.
* Assumes all your memory is Trendata or the non-Trendata
0x01, "C00", 0x02, "C01", 0x04, "C02", 0x08, "C03",
0x10, "C04", 0x19, "L01", 0x1A, "L02", 0x1C, "L04",
0x1F, "L07", 0x20, "C05", 0x38, "L00", 0x3B, "L03",
0x3D, "L05", 0x3E, "L06", 0x40, "C06", 0x49, "L09",
0x4A, "L10", 0x4c, "L12", 0x4F, "L15", 0x51, "L17",
0x52, "L18", 0x54, "L20", 0x57, "L23", 0x58, "L24",
0x5B, "L27", 0x5D, "L29", 0x5E, "L30", 0x68, "L08",
0x6B, "L11", 0x6D, "L13", 0x6E, "L14", 0x70, "L16",
0x73, "L19", 0x75, "L21", 0x76, "L22", 0x79, "L25",
0x7A, "L26", 0x7C, "L28", 0x7F, "L31", 0x80, "C07",
0x89, "U01", 0x8A, "U02", 0x8C, "U04", 0x8F, "U07",
0x91, "U09", 0x92, "U10", 0x94, "U12", 0x97, "U15",
0x98, "U16", 0x9B, "U19", 0x9D, "U21", 0x9E, "U22",
0xA8, "U00", 0xAB, "U03", 0xAD, "U05", 0xAE, "U06",
0xB0, "U08", 0xB3, "U11", 0xB5, "U13", 0xB6, "U14",
0xB9, "U17", 0xBA, "U18", 0xBC, "U20", 0xBF, "U23",
0xC1, "U25", 0xC2, "U26", 0xC4, "U28", 0xC7, "U31",
0xE0, "U24", 0xE3, "U27", 0xE5, "U29", 0xE6, "U30"
for (i
= 0; i
< (sizeof (memlogtab
) / sizeof (memlogtab
[0])); i
++)
if ((u_char
)(M780_SYN(mcr
)) == memlogtab
[i
].m_syndrome
) {
"mcr%d: replace %s chip in %s bank of memory board %d (0-15)\n",
(M780_ADDR(mcr
) & 0x8000) ? "upper" : "lower",
printf ("mcr%d: multiple errors, not traceable\n", m
);
* Invalidate single all pte's in a cluster
register caddr_t addr
; /* must be first reg var */
for (i
= 0; i
< CLSIZE
; i
++) {
register int howto
; /* r11 == how to boot */
register int devtype
; /* r10 == major of root dev */
printf("howto %d, devtype %d\n", arghowto
, devtype
);
if ((howto
&RB_NOSYNC
)==0 && waittime
< 0 && bfreelist
[0].b_forw
) {
printf("syncing disks... ");
{ register struct buf
*bp
;
for (iter
= 0; iter
< 10; iter
++) {
for (bp
= &buf
[nbuf
]; --bp
>= buf
; )
if (bp
->b_flags
& B_BUSY
)
splx(0x1f); /* extreme priority */
devtype
= major(rootdev
);
printf("halting (in tight loop); hit\n\t^P\n\tHALT\n\n");
if (paniced
== RB_PANIC
) {
doadump(); /* TXDB_BOOT's itsself */
#if defined(VAX750) || defined(VAX730)
{ asm("movl r11,r5"); } /* boot flags go in r5 */
while ((mfpr(TXCS
)&TXCS_RDY
) == 0)
* Doadump comes here after turning off memory management and
* getting on the dump stack, either when called above, or by
if ((minor(dumpdev
)&07) != 1)
printf("\ndumping to dev %x, offset %d\n", dumpdev
, dumplo
);
switch ((*bdevsw
[major(dumpdev
)].d_dump
)(dumpdev
)) {
printf("device not ready\n");
printf("area improper\n");
* Machine check error recovery code.
* Print out the machine check frame and then give up.
#if defined(VAX780) || defined(VAX750)
"cp read", "ctrl str par", "cp tbuf par", "cp cache par",
"cp rdtimo", "cp rds", "ucode lost", 0,
"ib rds", "ib rd timo", 0, "ib cache par"
"tb par", "bad retry", "bad intr id", "cant write ptem",
"unkn mcr err", "iib rd err", "nxm ref", "cp rds",
"unalgn ioref", "nonlw ioref", "bad ioaddr", "unalgn ubaddr",
int mc8_bcnt
; /* byte count == 0x28 */
int mc8_summary
; /* summary parameter (as above) */
int mc8_cpues
; /* cpu error status */
int mc8_upc
; /* micro pc */
int mc8_vaviba
; /* va/viba register */
int mc8_dreg
; /* d register */
int mc8_tber0
; /* tbuf error reg 0 */
int mc8_tber1
; /* tbuf error reg 1 */
int mc8_timo
; /* timeout address divided by 4 */
int mc8_parity
; /* parity */
int mc8_sbier
; /* sbi error register */
int mc8_pc
; /* trapped pc */
int mc8_psl
; /* trapped psl */
int mc5_bcnt
; /* byte count == 0x28 */
int mc5_summary
; /* summary parameter (as above) */
int mc5_va
; /* virtual address register */
int mc5_errpc
; /* error pc */
int mc5_svmode
; /* saved mode register */
int mc5_rdtimo
; /* read lock timeout */
int mc5_tbgpar
; /* tb group parity error register */
int mc5_cacherr
; /* cache error register */
int mc5_buserr
; /* bus error register */
int mc5_mcesr
; /* machine check status register */
int mc5_pc
; /* trapped pc */
int mc5_psl
; /* trapped psl */
int mc3_bcnt
; /* byte count == 0xc */
int mc3_summary
; /* summary parameter */
int mc3_parm
[2]; /* parameter 1 and 2 */
int mc3_pc
; /* trapped pc */
int mc3_psl
; /* trapped psl */
register u_int type
= ((struct mc780frame
*)cmcf
)->mc8_summary
;
printf("machine check %x: ", type
);
#if defined(VAX780) || defined(VAX750)
printf("%s%s\n", mc780
[type
&0xf],
(type
&0xf0) ? " abort" : " fault");
printf("%s", mc730
[type
]);
register struct mc780frame
*mcf
= (struct mc780frame
*)cmcf
;
printf("\tcpues %x upc %x va/viba %x dreg %x tber %x %x\n",
mcf
->mc8_cpues
, mcf
->mc8_upc
, mcf
->mc8_vaviba
,
mcf
->mc8_dreg
, mcf
->mc8_tber0
, mcf
->mc8_tber1
);
printf("\ttimo %x parity %x sbier %x pc %x psl %x sbifs %x\n",
mcf
->mc8_timo
*4, mcf
->mc8_parity
, mcf
->mc8_sbier
,
mcf
->mc8_pc
, mcf
->mc8_psl
, sbifs
);
/* THE FUNNY BITS IN THE FOLLOWING ARE FROM THE ``BLACK */
/* BOOK'' AND SHOULD BE PUT IN AN ``sbi.h'' */
mtpr(SBIFS
, sbifs
&~ 0x2000000);
mtpr(SBIER
, mfpr(SBIER
) | 0x70c0);
register struct mc750frame
*mcf
= (struct mc750frame
*)cmcf
;
printf("\tva %x errpc %x mdr %x smr %x rdtimo %x tbgpar %x cacherr %x\n",
mcf
->mc5_va
, mcf
->mc5_errpc
, mcf
->mc5_mdr
, mcf
->mc5_svmode
,
mcf
->mc5_rdtimo
, mcf
->mc5_tbgpar
, mcf
->mc5_cacherr
);
printf("\tbuserr %x mcesr %x pc %x psl %x mcsr %x\n",
mcf
->mc5_buserr
, mcf
->mc5_mcesr
, mcf
->mc5_pc
, mcf
->mc5_psl
,
if ((type
&0xf)==MC750_TBPAR
) {
printf("tbuf par!?!: flushing and returning\n");
register struct mc730frame
*mcf
= (struct mc730frame
*)cmcf
;
printf("params %x,%x pc %x psl %x mcesr %x\n",
mcf
->mc3_parm
[0], mcf
->mc3_parm
[1],
mcf
->mc3_pc
, mcf
->mc3_psl
, mfpr(MCESR
));
tvp
->tv_sec
= time
.tv_sec
;
tvp
->tv_usec
= (lbolt
+1)*16667 + mfpr(ICR
);
while (tvp
->tv_usec
> 1000000) {