Revamp the RID allocation code:

o  Limit the size of the region ID map to 64KB. This gives a bitmap
   that is large enough to keep track of 2^19 numbers. The minimal map
   size is 32KB. The reason we limit the map size is that processor
   models may have implemented a 24-bit region ID, which would give
   a 2MB bitmap while the maximum number of allocations is always
   less than PID_MAX*5, which is less than 2^19.
o  Allocate all region IDs up-front. The slight downside of reserving
   more RIDs then a process needs (3 for ia64 native and 1 for ia32)
   is preferable over the call to pmap_ensure_rid() where RIDs are
   allocated on demand. On SMP systems this may lead to a race
   condition.
o  When allocating a region ID, don't use arc4random(). We're not
   interested in randomness or uniform distribution across the
   spectrum. We only need uniqueness. Random numbers may easily
   collide when the number of allocated RIDs is high, creating a
   possibly unbounded retry rate.
This commit is contained in:
marcel 2003-05-16 06:40:40 +00:00
parent d3715e0039
commit 6a36805952

View File

@ -220,8 +220,11 @@ static u_int64_t pmap_ptc_e_stride2 = 0x100000000;
/*
* Data for the RID allocator
*/
static u_int64_t *pmap_ridbusy;
static int pmap_ridmax, pmap_ridcount;
static int pmap_ridcount;
static int pmap_rididx;
static int pmap_ridmapsz;
static int pmap_ridmax;
static u_int64_t *pmap_ridmap;
struct mtx pmap_ridmutex;
/*
@ -322,6 +325,24 @@ pmap_bootstrap()
/*
* Setup RIDs. RIDs 0..7 are reserved for the kernel.
*
* We currently need at least 19 bits in the RID because PID_MAX
* can only be encoded in 17 bits and we need RIDs for 5 regions
* per process. With PID_MAX equalling 99999 this means that we
* need to be able to encode 499995 (=5*PID_MAX).
* The Itanium processor only has 18 bits and the architected
* minimum is exactly that. So, we cannot use a PID based scheme
* in those cases. Enter pmap_ridmap...
* We should avoid the map when running on a processor that has
* implemented enough bits. This means that we should pass the
* process/thread ID to pmap. This we currently don't do, so we
* use the map anyway. However, we don't want to allocate a map
* that is large enough to cover the range dictated by the number
* of bits in the RID, because that may result in a RID map of
* 2MB in size for a 24-bit RID. A 64KB map is enough.
* The bottomline: we create a 32KB map when the processor only
* implements 18 bits (or when we can't figure it out). Otherwise
* we create a 64KB map.
*/
res = ia64_call_pal_static(PAL_VM_SUMMARY, 0, 0, 0);
if (res.pal_status != 0) {
@ -332,14 +353,17 @@ pmap_bootstrap()
ridbits = (res.pal_result[1] >> 8) & 0xff;
if (bootverbose)
printf("Processor supports %d Region ID bits\n",
ridbits);
ridbits);
}
if (ridbits > 19)
ridbits = 19;
pmap_ridmax = (1 << ridbits);
pmap_ridmapsz = pmap_ridmax / 64;
pmap_ridmap = (u_int64_t *)pmap_steal_memory(pmap_ridmax / 8);
pmap_ridmap[0] |= 0xff;
pmap_rididx = 0;
pmap_ridcount = 8;
pmap_ridbusy = (u_int64_t *)
pmap_steal_memory(pmap_ridmax / 8);
bzero(pmap_ridbusy, pmap_ridmax / 8);
pmap_ridbusy[0] |= 0xff;
mtx_init(&pmap_ridmutex, "RID allocator lock", NULL, MTX_DEF);
/*
@ -630,16 +654,31 @@ pmap_invalidate_all(pmap_t pmap)
static u_int32_t
pmap_allocate_rid(void)
{
uint64_t bit, bits;
int rid;
mtx_lock(&pmap_ridmutex);
if (pmap_ridcount == pmap_ridmax)
panic("pmap_allocate_rid: All Region IDs used");
do {
rid = arc4random() & (pmap_ridmax - 1);
} while (pmap_ridbusy[rid / 64] & (1L << (rid & 63)));
pmap_ridbusy[rid / 64] |= (1L << (rid & 63));
/* Find an index with a free bit. */
while ((bits = pmap_ridmap[pmap_rididx]) == ~0UL) {
pmap_rididx++;
if (pmap_rididx == pmap_ridmapsz)
pmap_rididx = 0;
}
rid = pmap_rididx * 64;
/* Find a free bit. */
bit = 1UL;
while (bits & bit) {
rid++;
bit <<= 1;
}
pmap_ridmap[pmap_rididx] |= bit;
pmap_ridcount++;
mtx_unlock(&pmap_ridmutex);
return rid;
}
@ -647,39 +686,18 @@ pmap_allocate_rid(void)
static void
pmap_free_rid(u_int32_t rid)
{
uint64_t bit;
int idx;
idx = rid / 64;
bit = ~(1UL << (rid & 63));
mtx_lock(&pmap_ridmutex);
pmap_ridbusy[rid / 64] &= ~(1L << (rid & 63));
pmap_ridmap[idx] &= bit;
pmap_ridcount--;
mtx_unlock(&pmap_ridmutex);
}
static void
pmap_ensure_rid(pmap_t pmap, vm_offset_t va)
{
int rr;
rr = va >> 61;
/*
* We get called for virtual addresses that may just as well be
* kernel addresses (ie region 5, 6 or 7). Since the pm_rid field
* only holds region IDs for user regions, we have to make sure
* the region is within bounds.
*/
if (rr >= 5)
return;
if (pmap->pm_rid[rr])
return;
mtx_lock(&pmap_ridmutex);
pmap->pm_rid[rr] = pmap_allocate_rid();
if (pmap == PCPU_GET(current_pmap))
ia64_set_rr(IA64_RR_BASE(rr),
(pmap->pm_rid[rr] << 8)|(PAGE_SHIFT << 2)|1);
mtx_unlock(&pmap_ridmutex);
}
/***************************************************
* Low level helper routines.....
***************************************************/
@ -867,6 +885,10 @@ pmap_pinit(struct pmap *pmap)
void
pmap_pinit2(struct pmap *pmap)
{
int i;
for (i = 0; i < 5; i++)
pmap->pm_rid[i] = pmap_allocate_rid();
}
/***************************************************
@ -1666,8 +1688,6 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
if (pmap == NULL)
return;
pmap_ensure_rid(pmap, va);
oldpmap = pmap_install(pmap);
va &= ~PAGE_MASK;
@ -1784,8 +1804,6 @@ pmap_enter_quick(pmap_t pmap, vm_offset_t va, vm_page_t m)
struct ia64_lpte *pte;
pmap_t oldpmap;
pmap_ensure_rid(pmap, va);
oldpmap = pmap_install(pmap);
pte = pmap_find_pte(va);