s = splvm();
s = splpmap();
ctx_alloc(pm)	struct pmap *pm;{	union ctxinfo *c;	int s, cnum, i, doflush;	struct regmap *rp;	int gap_start, gap_end;	unsigned long va;/*XXX-GCC!*/gap_start=gap_end=0;#ifdef DEBUG	if (pm->pm_ctx)		panic("ctx_alloc pm_ctx");	if (pmapdebug & PDB_CTX_ALLOC)		printf("ctx_alloc(%p)\n", pm);#endif	if (CPU_ISSUN4OR4C) {		gap_start = pm->pm_gap_start;		gap_end = pm->pm_gap_end;	}	s = splvm();	if ((c = ctx_freelist) != NULL) {		ctx_freelist = c->c_nextfree;		cnum = c - cpuinfo.ctxinfo;		doflush = 0;	} else {		if ((ctx_kick += ctx_kickdir) >= ncontext) {			ctx_kick = ncontext - 1;			ctx_kickdir = -1;		} else if (ctx_kick < 1) {			ctx_kick = 1;			ctx_kickdir = 1;		}		c = &cpuinfo.ctxinfo[cnum = ctx_kick];#ifdef DEBUG		if (c->c_pmap == NULL)			panic("ctx_alloc cu_pmap");		if (pmapdebug & (PDB_CTX_ALLOC | PDB_CTX_STEAL))			printf("ctx_alloc: steal context %d from %p\n",			    cnum, c->c_pmap);#endif		c->c_pmap->pm_ctx = NULL;		doflush = (CACHEINFO.c_vactype != VAC_NONE);		if (CPU_ISSUN4OR4C) {			if (gap_start < c->c_pmap->pm_gap_start)				gap_start = c->c_pmap->pm_gap_start;			if (gap_end > c->c_pmap->pm_gap_end)				gap_end = c->c_pmap->pm_gap_end;		}	}	c->c_pmap = pm;	pm->pm_ctx = c;	pm->pm_ctxnum = cnum;	if (CPU_ISSUN4OR4C) {		/*		 * Write pmap's region (3-level MMU) or segment table into		 * the MMU.		 *		 * Only write those entries that actually map something in		 * this context by maintaining a pair of region numbers in		 * between which the pmap has no valid mappings.		 *		 * If a context was just allocated from the free list, trust		 * that all its pmeg numbers are `seginval'. We make sure this		 * is the case initially in pmap_bootstrap(). Otherwise, the		 * context was freed by calling ctx_free() in pmap_release(),		 * which in turn is supposedly called only when all mappings		 * have been removed.		 *		 * On the other hand, if the context had to be stolen from		 * another pmap, we possibly shrink the gap to be the		 * disjuction of the new and the previous map.		 */		setcontext4(cnum);		splx(s);		if (doflush)			cache_flush_context();		rp = pm->pm_regmap;		for (va = 0, i = NUREG; --i >= 0; ) {			if (VA_VREG(va) >= gap_start) {				va = VRTOVA(gap_end);				i -= gap_end - gap_start;				rp += gap_end - gap_start;				if (i < 0)					break;				/* mustn't re-enter this branch */				gap_start = NUREG;			}			if (HASSUN4_MMU3L) {				setregmap(va, rp++->rg_smeg);				va += NBPRG;			} else {				int j;				struct segmap *sp = rp->rg_segmap;				for (j = NSEGRG; --j >= 0; va += NBPSG)					setsegmap(va,						  sp?sp++->sg_pmeg:seginval);				rp++;			}		}	} else if (CPU_ISSUN4M) {#if defined(SUN4M)		/*		 * Reload page and context tables to activate the page tables		 * for this context.		 *		 * The gap stuff isn't really needed in the Sun4m architecture,		 * since we don't have to worry about excessive mappings (all		 * mappings exist since the page tables must be complete for		 * the mmu to be happy).		 *		 * If a context was just allocated from the free list, trust		 * that all of its mmu-edible page tables are zeroed out		 * (except for those associated with the kernel). We make		 * sure this is the case initially in pmap_bootstrap() and		 * pmap_init() (?).		 * Otherwise, the context was freed by calling ctx_free() in		 * pmap_release(), which in turn is supposedly called only		 * when all mappings have been removed.		 *		 * XXX: Do we have to flush cache after reloading ctx tbl?		 */		/* Do any cache flush needed on context switch */		(*cpuinfo.pure_vcache_flush)();#ifdef DEBUG#if 0		ctxbusyvector[cnum] = 1; /* mark context as busy */#endif		if (pm->pm_reg_ptps_pa == 0)			panic("ctx_alloc: no region table in current pmap");#endif		/*setcontext(0); * paranoia? can we modify curr. ctx? */		setpgt4m(&cpuinfo.ctx_tbl[cnum],			(pm->pm_reg_ptps_pa >> SRMMU_PPNPASHIFT) | SRMMU_TEPTD);		setcontext4m(cnum);		if (doflush)			cache_flush_context();		tlb_flush_context(); /* remove any remnant garbage from tlb */#endif		splx(s);	}}