* Copyright (c) 1988 Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)vm_machdep.c 7.2 (Berkeley) 7/9/88
* Set a red zone in the kernel stack after the u. area.
register struct pte
*pte
;
pte
+= (sizeof (struct user
) + NBPG
- 1) / NBPG
;
mtpr(TBIS
, vaddr
+ sizeof (struct user
) + NBPG
- 1);
* Check for valid program size
* NB - Check data and data growth separately as they may overflow
chksize(ts
, ids
, uds
, ss
)
register unsigned ts
, ids
, uds
, ss
;
extern unsigned maxtsize
;
if (ctob(ts
) > maxtsize
||
ctob(ids
) > u
.u_rlimit
[RLIMIT_DATA
].rlim_cur
||
ctob(uds
) > u
.u_rlimit
[RLIMIT_DATA
].rlim_cur
||
ctob(ids
+ uds
) > u
.u_rlimit
[RLIMIT_DATA
].rlim_cur
||
ctob(ss
) > u
.u_rlimit
[RLIMIT_STACK
].rlim_cur
) {
register struct pte
*pte
;
register caddr_t a
= ptob(v
);
* Change protection codes of text segment.
* Have to flush translation buffer since this
* affect virtual memory mapping of current process.
register struct pte
*pte
;
if (!isatsv(u
.u_procp
, v
)) {
tp
= vtotp(u
.u_procp
, v
);
pte
= tptopte(u
.u_procp
, tp
);
if (pte
->pg_fod
== 0 && pte
->pg_pfnum
) {
c
= &cmap
[pgtocm(pte
->pg_pfnum
)];
if (c
->c_blkno
&& c
->c_mdev
!= MSWAPX
)
munhash(mount
[c
->c_mdev
].m_dev
,
(daddr_t
)(u_long
)c
->c_blkno
);
ptaddr
= (int *)mfpr(P0BR
);
for (i
= 0; i
< u
.u_tsize
; i
++) {
* Rest are machine-dependent
*(int *)mmap
= PG_V
| PG_KR
| btop(addr
);
uncache(&vmmap
[(int)addr
& PGOFSET
]);
c
= *(char *)&vmmap
[(int)addr
& PGOFSET
];
*(int *)mmap
= PG_V
| PG_KW
| btop(addr
);
*(char *)&vmmap
[(int)addr
& PGOFSET
] = val
;
* Move pages from one kernel virtual address to another.
* Both addresses are assumed to reside in the Sysmap,
* and size must be a multiple of CLSIZE.
register caddr_t from
, to
;
register struct pte
*fpte
, *tpte
;
mtpr(P1DC
, to
); /* purge !! */
* Code and data key management routines.
* The array ckey_cnt maintains the count of processes currently
* sharing each code key. The array ckey_cache maintains a record
* of all code keys used since the last flush of the code cache.
* Such keys may not be reused, even if unreferenced, until
* the cache is flushed. The data cache key handling is analogous.
* The arrays ckey_cnt and ckey_cache are allways kept in such a way
* that the following invariant holds:
* ckey_cnt > 0 =>'s ckey_cache == 1
* meaning as long as a code key is used by at least one process, it's
* marked as being 'in the cache'. Of course, the following invariant
* ckey_cache == 0 =>'s ckey_cnt == 0
* which is just the reciprocal of the 1'st invariant.
* Equivalent invariants hold for the data key arrays.
struct keystats ckeystats
= { NCKEY
- 1 };
struct keystats dkeystats
= { NDKEY
- 1 };
if (--ckey_cnt
[key
] < 0) {
printf("ckeyrelease: key = %d\n", key
);
if (--dkey_cnt
[key
] != 0) {
printf("dkeyrelease: key = %d\n", key
);
* Invalidate the data cache for a process
* by exchanging cache keys.
if (--dkey_cnt
[p
->p_dkey
] != 0)
if (p
== u
.u_procp
&& !noproc
) {
p
->p_dkey
= getdatakey();
* Strategy: try each of the following in turn
* until a key is allocated.
* 1) Find an unreferenced key not yet in the cache.
* If this fails, a code cache purge will be necessary.
* 2) Find an unreferenced key. Mark all unreferenced keys
* as available and purge the cache.
* 3) Free the keys from all processes not sharing keys.
* 4) Free the keys from all processes.
register int i
, s
, freekey
;
static int lastkey
= MAXCKEY
;
for (i
= lastkey
+ 1; ; i
++) {
if ((int)ckey_cache
[i
] == 0) { /* free key, take it */
ckey_cache
[i
] = 1, ckey_cnt
[i
] = 1;
ckeystats
.ks_allocfree
++;
if (ckey_cnt
[i
] == 0) /* save for potential use */
* All code keys were marked as being in cache.
* If a key was in the cache, but not in use, grab it.
* If we've run out of free keys,
* try and free up some other keys to avoid
ckey_cnt
[freekey
] = 1, ckey_cache
[freekey
] = 1;
for (i
= 1; i
<= MAXCKEY
; i
++)
* All keys are marked as in the cache and in use.
* Release all unshared keys, or, on second pass,
for (p
= allproc
; p
; p
= p
->p_nxt
)
if (p
->p_ckey
!= 0 && (p
->p_flag
& SSYS
) == 0) {
if (ckey_cnt
[i
] == 1 || desparate
) {
if (--ckey_cnt
[i
] == 0) {
* 1) Try to find a data key that isn't in the cache. Allocate it.
* 2) If all data keys are in the cache, find one which isn't
* allocated. Mark all unallocated keys as not in cache,
* purge the cache, and allocate this one.
* 3) If all of them are allocated, free all process' keys
* and let them reclaim then as they run.
static int lastkey
= MAXDKEY
;
for (i
= lastkey
+ 1; ; i
++) {
if ((int)dkey_cache
[i
] == 0) { /* free key, take it */
dkey_cache
[i
] = 1, dkey_cnt
[i
] = 1;
dkeystats
.ks_allocfree
++;
* Try and free up some more keys to avoid
* future allocations causing a cache purge.
dkey_cnt
[freekey
] = 1, dkey_cache
[freekey
] = 1;
for (i
= 1; i
<= MAXDKEY
; i
++)
* Now, we have to take a key from someone.
* May as well take them all, so we get them
* from all of the idle procs.
for (p
= allproc
; p
; p
= p
->p_nxt
)
if (p
->p_dkey
!= 0 && (p
->p_flag
& SSYS
) == 0) {
register struct pte
*pte
;
pte
= &Sysmap
[pg
- BTOPKERNBASE
];
return ((pte
->pg_pfnum
<< PGSHIFT
) + (v
& PGOFSET
));