e4651682d6403b470567538b713ceb7886d6622f
* Copyright (c) 1992 The Regents of the University of California.
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratories.
* %sccs.include.redist.c%
* @(#)machdep.c 7.2 (Berkeley) %G%
* from: $Header: machdep.c,v 1.32 92/07/13 01:41:14 torek Exp $
#include "machine/autoconf.h"
#include "machine/frame.h"
extern vm_offset_t avail_end
;
* Declare these as initialized data so we can patch them.
extern struct msgbuf msgbuf
;
struct msgbuf
*msgbufp
= &msgbuf
;
int msgbufmapped
= 1; /* message buffer is always mapped */
* safepri is a safe priority for sleep to set for a spin-wait
* during autoconfiguration or after a panic.
* Machine-dependent startup code
int opmapdebug
= pmapdebug
;
vm_offset_t minaddr
, maxaddr
;
* Good {morning,afternoon,evening,night}.
physmem
= btoc(avail_end
);
printf("real mem = %d\n", avail_end
);
* Find out how much space we need, allocate it,
* and then give everything true virtual addresses.
sz
= (int)allocsys((caddr_t
)0);
if ((v
= (caddr_t
)kmem_alloc(kernel_map
, round_page(sz
))) == 0)
panic("startup: no room for tables");
if (allocsys(v
) - v
!= sz
)
panic("startup: table size inconsistency");
* Now allocate buffers proper. They are different than the above
* in that they usually occupy more virtual memory than physical.
buffer_map
= kmem_suballoc(kernel_map
, (vm_offset_t
*)&buffers
,
minaddr
= (vm_offset_t
)buffers
;
if (vm_map_find(buffer_map
, vm_object_allocate(size
), (vm_offset_t
)0,
&minaddr
, size
, FALSE
) != KERN_SUCCESS
)
panic("startup: cannot allocate buffers");
residual
= bufpages
% nbuf
;
for (i
= 0; i
< nbuf
; i
++) {
* First <residual> buffers get (base+1) physical pages
* allocated for them. The rest get (base) physical pages.
* The rest of each buffer occupies virtual space,
* but has no physical memory allocated for it.
curbuf
= (vm_offset_t
)buffers
+ i
* MAXBSIZE
;
curbufsize
= CLBYTES
* (i
< residual
? base
+1 : base
);
vm_map_pageable(buffer_map
, curbuf
, curbuf
+curbufsize
, FALSE
);
vm_map_simplify(buffer_map
, curbuf
);
* Allocate a submap for exec arguments. This map effectively
* limits the number of processes exec'ing at any time.
exec_map
= kmem_suballoc(kernel_map
, &minaddr
, &maxaddr
,
* Allocate a map for physio. Others use a submap of the kernel
* map, but we want one completely separate, even though it uses
phys_map
= vm_map_create(kernel_pmap
, DVMA_BASE
, DVMA_END
, 1);
panic("unable to create DVMA map");
* Finally, allocate mbuf pool. Since mclrefcnt is an off-size
* we use the more space efficient malloc in place of kmem_alloc.
mclrefcnt
= (char *)malloc(NMBCLUSTERS
+CLBYTES
/MCLBYTES
,
bzero(mclrefcnt
, NMBCLUSTERS
+CLBYTES
/MCLBYTES
);
mb_map
= kmem_suballoc(kernel_map
, (vm_offset_t
*)&mbutl
, &maxaddr
,
for (i
= 1; i
< ncallout
; i
++)
callout
[i
-1].c_next
= &callout
[i
];
callout
[i
-1].c_next
= NULL
;
printf("avail mem = %d\n", ptoa(cnt
.v_free_count
));
printf("using %d buffers containing %d bytes of memory\n",
nbuf
, bufpages
* CLBYTES
);
* Set up buffers, so they can be used to read disk labels.
* Turn on the cache (do after configuration due to a bug in
* some versions of the SPARC chips -- this info from Gilmore).
* Allocate space for system data structures. We are given
* a starting virtual address and we return a final virtual
* address; along the way we set each data structure pointer.
* You call allocsys() with 0 to find out how much space we want,
* allocate that much and fill it with zeroes, and then call
* allocsys() again with the correct base virtual address.
#define valloc(name, type, num) \
v = (caddr_t)(((name) = (type *)v) + (num))
valloc(cfree
, struct cblock
, nclist
);
valloc(callout
, struct callout
, ncallout
);
valloc(swapmap
, struct map
, nswapmap
= maxproc
* 2);
valloc(shmsegs
, struct shmid_ds
, shminfo
.shmmni
);
* Determine how many buffers to allocate (enough to
* hold 5% of total physical memory, but at least 16).
* Allocate 1/2 as many swap buffer headers as file i/o buffers.
bufpages
= (physmem
/ 20) / CLSIZE
;
nswbuf
= (nbuf
/ 2) &~ 1; /* force even */
nswbuf
= 256; /* sanity */
valloc(swbuf
, struct buf
, nswbuf
);
valloc(buf
, struct buf
, nbuf
);
* Set up registers on exec.
* XXX this entire mess must be fixed
setregs(p
, entry
, retval
)
register struct trapframe
*tf
= p
->p_md
.md_tf
;
register struct fpstate
*fs
;
* The syscall will ``return'' to npc or %g7 or %g2; set them all.
* Set the rest of the registers to 0 except for %o6 (stack pointer,
* built in exec()) and psr (retain CWP and PSR_S bits).
psr
= tf
->tf_psr
& (PSR_S
| PSR_CWP
);
if ((fs
= p
->p_md
.md_fpstate
) != NULL
) {
* We hold an FPU state. If we own *the* FPU chip state
* we must get rid of it, and the only way to do that is
* to save it. In any case, get rid of our FPU state.
free((void *)fs
, M_SUBPROC
);
p
->p_md
.md_fpstate
= NULL
;
bzero((caddr_t
)tf
, sizeof *tf
);
tf
->tf_global
[2] = tf
->tf_global
[7] = tf
->tf_npc
= entry
& ~3;
int sf_signo
; /* signal number */
struct sigcontext
*sf_scp
; /* points to user addr of sigcontext */
int sf_xxx
; /* placeholder */
int sf_addr
; /* SunOS compat, always 0 for now */
struct sigcontext sf_sc
; /* actual sigcontext */
* Send an interrupt to process.
sendsig(catcher
, sig
, mask
, code
)
register struct proc
*p
= curproc
;
register struct sigacts
*psp
= p
->p_sigacts
;
register struct sigframe
*fp
;
register struct trapframe
*tf
;
register int addr
, oonstack
;
extern char sigcode
[], esigcode
[];
#define szsigcode (esigcode - sigcode)
oonstack
= psp
->ps_sigstk
.ss_flags
& SA_ONSTACK
;
* Compute new user stack addresses, subtract off
* one signal frame, and align.
if ((psp
->ps_flags
& SAS_ALTSTACK
) && !oonstack
&&
(psp
->ps_sigonstack
& sigmask(sig
))) {
fp
= (struct sigframe
*)(psp
->ps_sigstk
.ss_base
+
psp
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
fp
= (struct sigframe
*)tf
->tf_out
[6];
fp
= (struct sigframe
*)((int)(fp
- 1) & ~7);
if ((sigdebug
& SDB_KSTACK
) && p
->p_pid
== sigpid
)
printf("sendsig: %s[%d] sig %d newusp %x scp %x\n",
p
->p_comm
, p
->p_pid
, sig
, fp
, &fp
->sf_sc
);
* Now set up the signal frame. We build it in kernel space
* and then copy it out. We probably ought to just build it
* directly in user space....
sf
.sf_addr
= 0; /* XXX */
* Build the signal context to be used by sigreturn.
sf
.sf_sc
.sc_onstack
= oonstack
;
sf
.sf_sc
.sc_sp
= tf
->tf_out
[6];
sf
.sf_sc
.sc_pc
= tf
->tf_pc
;
sf
.sf_sc
.sc_npc
= tf
->tf_npc
;
sf
.sf_sc
.sc_psr
= tf
->tf_psr
;
sf
.sf_sc
.sc_g1
= tf
->tf_global
[1];
sf
.sf_sc
.sc_o0
= tf
->tf_out
[0];
* Put the stack in a consistent state before we whack away
* at it. Note that write_user_windows may just dump the
* registers into the pcb; we need them in the process's memory.
if (rwindow_save(p
) || copyout((caddr_t
)&sf
, (caddr_t
)fp
, sizeof sf
)) {
* Process has trashed its stack; give it an illegal
* instruction to halt it in its tracks.
if ((sigdebug
& SDB_KSTACK
) && p
->p_pid
== sigpid
)
printf("sendsig: window save or copyout error\n");
if (sigdebug
& SDB_FOLLOW
)
printf("sendsig: %s[%d] sig %d scp %x\n",
p
->p_comm
, p
->p_pid
, sig
, &fp
->sf_sc
);
* Arrange to continue execution at the code copied out in exec().
* It needs the function to call in %g1, and a new stack pointer.
if (psp
->ps_usertramp
& sigmask(sig
)) {
addr
= (int)catcher
; /* user does his own trampolining */
addr
= USRSTACK
- sizeof(struct ps_strings
) - szsigcode
;
tf
->tf_global
[1] = (int)catcher
;
tf
->tf_out
[6] = (int)fp
- sizeof(struct rwindow
);
if ((sigdebug
& SDB_KSTACK
) && p
->p_pid
== sigpid
)
printf("sendsig: about to return to catcher\n");
* System call to cleanup state after a signal
* has been taken. Reset signal mask and
* stack state from context left by sendsig (above),
* and return to the given trap frame (if there is one).
* Check carefully to make sure that the user has not
* modified the state to gain improper privileges or to cause
sigreturn(p
, uap
, retval
)
struct sigreturn_args
*uap
;
register struct sigcontext
*scp
;
register struct trapframe
*tf
;
/* First ensure consistent stack state (see sendsig). */
if (sigdebug
& SDB_FOLLOW
)
printf("sigreturn: %s[%d], scp %x\n",
p
->p_comm
, p
->p_pid
, uap
->scp
);
if ((int)scp
& 3 || useracc((caddr_t
)scp
, sizeof *scp
, B_WRITE
) == 0)
* Only the icc bits in the psr are used, so it need not be
* verified. pc and npc must be multiples of 4. This is all
* that is required; if it holds, just do it.
if (((scp
->sc_pc
| scp
->sc_npc
) & 3) != 0)
/* take only psr ICC field */
tf
->tf_psr
= (tf
->tf_psr
& ~PSR_ICC
) | (scp
->sc_psr
& PSR_ICC
);
tf
->tf_npc
= scp
->sc_npc
;
tf
->tf_global
[1] = scp
->sc_g1
;
tf
->tf_out
[0] = scp
->sc_o0
;
tf
->tf_out
[6] = scp
->sc_sp
;
p
->p_sigacts
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
p
->p_sigacts
->ps_sigstk
.ss_flags
&= ~SA_ONSTACK
;
p
->p_sigmask
= scp
->sc_mask
& ~sigcantmask
;
static char str
[4]; /* room for "-sd\0" */
extern volatile void romhalt(void);
extern volatile void romboot(char *);
if ((howto
& RB_NOSYNC
) == 0 && waittime
< 0 && rootfs
) {
extern struct proc proc0
;
/* protect against curproc->p_stats.foo refs in sync() XXX */
printf("syncing disks... ");
* Release vnodes held by texts before sync.
vnode_pager_umount((struct mount
*)NULL
);
sync((struct proc
*)NULL
, (void *)NULL
, (int *)NULL
);
for (iter
= 0; iter
< 20; iter
++) {
for (bp
= &buf
[nbuf
]; --bp
>= buf
; )
if ((bp
->b_flags
& (B_BUSY
|B_INVAL
)) == B_BUSY
)
* If we've been adjusting the clock, the todr
* will be out of synch; adjust it now.
(void) splhigh(); /* ??? */
int dumpmag
= 0x8fca0101; /* magic number for savecore */
int dumpsize
= 0; /* also for savecore */
* savecore views the image in units of pages (i.e., dumpsize is in
* pages) so we round the two mmu entities into page-sized chunks.
* The PMEGs (32kB) and the segment table (512 bytes plus padding)
* are appending to the end of the crash dump.
dumpsize
+= btoc(sizeof(((struct kpmap
*)0)->pm_rsegmap
)) +
btoc(NPMEG
* NPTESG
* sizeof(int));
if (dumpdev
!= NODEV
&& bdevsw
[major(dumpdev
)].d_psize
) {
nblks
= (*bdevsw
[major(dumpdev
)].d_psize
)(dumpdev
);
* Don't dump on the first CLBYTES (why CLBYTES?)
* in case the dump device includes a disk label.
if (dumplo
< btodb(CLBYTES
))
* If dumpsize is too big for the partition, truncate it.
* Otherwise, put the dump at the end of the partition
* by making dumplo as large as possible.
if (dumpsize
> btoc(dbtob(nblks
- dumplo
)))
dumpsize
= btoc(dbtob(nblks
- dumplo
));
else if (dumplo
+ ctod(dumpsize
) > nblks
)
dumplo
= nblks
- ctod(dumpsize
);
#define getpte(va) lda(va, ASI_PTE)
#define setsegmap(va, pmeg) stba(va, ASI_SEGMAP, pmeg)
* Write the mmu contents to the dump device.
* This gets appended to the end of a crash dump since
* there is no in-core copy of kernel memory mappings.
register int (*dump
)(/*dev_t, daddr_t, caddr_t, int*/);
register int addr
; /* unused kernel virtual address */
register int *pte
, *ptend
;
register struct kpmap
*kpmap
= &kernel_pmap_store
;
int buffer
[dbtob(1) / sizeof(int)];
extern int seginval
; /* from pmap.c */
dump
= bdevsw
[major(dumpdev
)].d_dump
;
* dump page table entries
* We dump each pmeg in order (by segment number). Since the MMU
* automatically maps the given virtual segment to a pmeg we must
* iterate over the segments by incrementing an unused segment slot
* in the MMU. This fixed segment number is used in the virtual
* address argument to getpte().
/* First find an unused virtual segment. */
while (kpmap
->pm_rsegmap
[--i
] != seginval
)
* Compute the base address corresponding to the unused segment.
* Note that the kernel segments start after all the user segments
* so we must account for this offset.
addr
= VSTOVA(i
+ NUSEG
);
* Go through the pmegs and dump each one.
ptend
= &buffer
[sizeof(buffer
) / sizeof(buffer
[0])];
for (pmeg
= 0; pmeg
< NPMEG
; ++pmeg
) {
* Note that we'll dump the last block
* the last time through the loops because
* all the PMEGs occupy 32KB which is
* a multiple of the block size.
error
= (*dump
)(dumpdev
, blkno
,
setsegmap(addr
, seginval
);
* dump (512 byte) segment map
* XXX assume it's a multiple of the block size
error
= (*dump
)(dumpdev
, blkno
, (caddr_t
)kpmap
->pm_rsegmap
,
sizeof(kpmap
->pm_rsegmap
), 0);
#define BYTES_PER_DUMP (32 * 1024) /* must be a multiple of pagesize */
static vm_offset_t dumpspace
;
dumpspace
= (vm_offset_t
)p
;
return (p
+ BYTES_PER_DUMP
);
register unsigned bytes
, i
, n
;
register int maddr
, psize
;
register int (*dump
)(/*dev_t, daddr_t, caddr_t, int, int*/);
/* copy registers to memory */
* For dumps during autoconfiguration,
* if dump device has already configured...
printf("\ndumping to dev %x, offset %d\n", dumpdev
, dumplo
);
psize
= (*bdevsw
[major(dumpdev
)].d_psize
)(dumpdev
);
printf("area unavailable\n");
bytes
= physmem
<< PGSHIFT
;
dump
= bdevsw
[major(dumpdev
)].d_dump
;
for (i
= 0; i
< bytes
; i
+= n
) {
/* print out how many MBs we have dumped */
if (i
&& (i
% (1024*1024)) == 0)
printf("%d ", i
/ (1024*1024));
(void) pmap_map(dumpspace
, maddr
, maddr
+ n
, VM_PROT_READ
);
error
= (*dump
)(dumpdev
, blkno
, (caddr_t
)dumpspace
, (int)n
);
printf("device not ready\n");
printf("area improper\n");
printf("error %d\n", error
);
* Map an I/O device given physical address and size in bytes, e.g.,
* mydev = (struct mydev *)mapdev(myioaddr, 0, sizeof(struct mydev));
* See also machine/autoconf.h.
static vm_offset_t iobase
= IODEV_BASE
;
if (iobase
> IODEV_END
) /* unlikely */
pmap_enter(kernel_pmap
, v
,
(vm_offset_t
)phys
| PMAP_OBIO
| PMAP_NC
,
VM_PROT_READ
| VM_PROT_WRITE
, 1);
} while ((size
-= PAGE_SIZE
) > 0);