+/*
+ * No free mappings. First, there may be some mapping blocks on the "to be released"
+ * list. If so, rescue one. Otherwise, try to steal a couple blocks worth.
+ */
+
+ if((mbn = mapCtl.mapcrel) != 0) { /* Try to rescue a block from impending doom */
+ mapCtl.mapcrel = mbn->nextblok; /* Pop the queue */
+ mapCtl.mapcreln--; /* Back off the count */
+ mapping_free_init((vm_offset_t)mbn, 0, 1); /* Initialize a non-permanent block */
+ goto rescued;
+ }
+
+ hw_lock_unlock((hw_lock_t)&mapCtl.mapclock);
+
+ simple_lock(&free_pmap_lock);
+
+ if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */
+ panic("mapping_alloc - timeout getting control lock\n"); /* Tell all and die */
+ }
+
+ if (!((unsigned int)mapCtl.mapcnext)) {
+
+ refpmap = (pmap_t)cursor_pmap->pmap_link.next;
+ space = mapCtl.mapcflush.spacenum;
+ while (refpmap != cursor_pmap) {
+ if(((pmap_t)(refpmap->pmap_link.next))->spaceNum > space) break;
+ refpmap = (pmap_t)refpmap->pmap_link.next;
+ }
+
+ ckpmap = refpmap;
+ va = mapCtl.mapcflush.addr;
+ found_mapping = FALSE;
+
+ while (mapCtl.mapcfree <= (MAPPERBLOK*2)) {
+
+ hw_lock_unlock((hw_lock_t)&mapCtl.mapclock);
+
+ ckpmap = (pmap_t)ckpmap->pmap_link.next;
+
+ /* We don't steal mappings from the kernel pmap, a VMM host pmap, or a VMM guest pmap with guest
+ shadow assist active.
+ */
+ if ((ckpmap->stats.resident_count != 0) && (ckpmap != kernel_pmap)
+ && !(ckpmap->pmapFlags & (pmapVMgsaa|pmapVMhost))) {
+ do_rescan = TRUE;
+ for (i=0;i<8;i++) {
+ mp = hw_purge_map(ckpmap, va, &nextva);
+
+ switch ((unsigned int)mp & mapRetCode) {
+ case mapRtOK:
+ mapping_free(mp);
+ found_mapping = TRUE;
+ break;
+ case mapRtNotFnd:
+ break;
+ default:
+ panic("mapping_alloc: hw_purge_map failed - pmap = %08X, va = %16llX, code = %08X\n", ckpmap, va, mp);
+ break;
+ }
+
+ if (mapRtNotFnd == ((unsigned int)mp & mapRetCode))
+ if (do_rescan)
+ do_rescan = FALSE;
+ else
+ break;
+
+ va = nextva;
+ }
+ }
+
+ if (ckpmap == refpmap) {
+ if (found_mapping == FALSE)
+ panic("no valid pmap to purge mappings\n");
+ else
+ found_mapping = FALSE;
+ }
+
+ if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) { /* Lock the control header */
+ panic("mapping_alloc - timeout getting control lock\n"); /* Tell all and die */
+ }
+
+ }
+
+ mapCtl.mapcflush.spacenum = ckpmap->spaceNum;
+ mapCtl.mapcflush.addr = nextva;
+ }
+
+ simple_unlock(&free_pmap_lock);
+ }
+
+rescued:
+
+ mb = mapCtl.mapcnext;
+
+ if ( big ) { /* if we need a big (128-byte) mapping */
+ mapCtl.mapcbig++; /* count attempts to allocate a big mapping */
+ mbn = NULL; /* this will be prev ptr */
+ mindx = 0;
+ while( mb ) { /* loop over mapping blocks with free entries */
+ mindx = mapalc2(mb); /* try for 2 consequtive free bits in this block */
+
+ if ( mindx ) break; /* exit loop if we found them */
+ mbn = mb; /* remember previous block */
+ mb = mb->nextblok; /* move on to next block */
+ }
+ if ( mindx == 0 ) { /* if we couldn't find 2 consequtive bits... */
+ mapCtl.mapcbigfails++; /* count failures */
+ big = 0; /* forget that we needed a big mapping */
+ lists = mpBasicLists; /* clamp list count down to the max in a 64-byte mapping */
+ mb = mapCtl.mapcnext; /* back to the first block with a free entry */
+ }
+ else { /* if we did find a big mapping */
+ mapCtl.mapcfree--; /* Decrement free count twice */
+ mapCtl.mapcinuse++; /* Bump in use count twice */
+ if ( mindx < 0 ) { /* if we just used the last 2 free bits in this block */
+ if (mbn) { /* if this wasn't the first block */
+ mindx = -mindx; /* make positive */
+ mbn->nextblok = mb->nextblok; /* unlink this one from the middle of block list */
+ if (mb == mapCtl.mapclast) { /* if we emptied last block */
+ mapCtl.mapclast = mbn; /* then prev block is now last */
+ }
+ }
+ }
+ }
+ }
+
+ if ( !big ) { /* if we need a small (64-byte) mapping */
+ if(!(mindx = mapalc1(mb))) /* Allocate a 1-bit slot */
+ panic("mapping_alloc - empty mapping block detected at %08X\n", mb);
+ }