vm: implement B_RANDOMIZED_BASE_ADDRESS address specification
B_RAND_BASE_ADDRESS is basically B_BASE_ADDRESS with non-deterministic created area's base address. Initial start address is randomized and then the algorithm looks for a large enough free space in the interval [randomized start, end]. If it fails then the search is repeated in the interval [original start, randomized start]. In case it also fails the algorithm falls back to B_ANY_ADDRESS (B_RANDOMIZED_ANY_ADDRESS when it is implemented) just like B_BASE_ADDRESS does. Randomization range is limited by kMaxRandomize and kMaxInitialRandomize.
This commit is contained in:
@@ -73,11 +73,14 @@ typedef struct area_info {
|
|||||||
#define B_32_BIT_CONTIGUOUS 6 /* B_CONTIGUOUS, < 4 GB physical address */
|
#define B_32_BIT_CONTIGUOUS 6 /* B_CONTIGUOUS, < 4 GB physical address */
|
||||||
|
|
||||||
/* address spec for create_area(), and clone_area() */
|
/* address spec for create_area(), and clone_area() */
|
||||||
#define B_ANY_ADDRESS 0
|
#define B_ANY_ADDRESS 0
|
||||||
#define B_EXACT_ADDRESS 1
|
#define B_EXACT_ADDRESS 1
|
||||||
#define B_BASE_ADDRESS 2
|
#define B_BASE_ADDRESS 2
|
||||||
#define B_CLONE_ADDRESS 3
|
#define B_CLONE_ADDRESS 3
|
||||||
#define B_ANY_KERNEL_ADDRESS 4
|
#define B_ANY_KERNEL_ADDRESS 4
|
||||||
|
/* B_ANY_KERNEL_BLOCK_ADDRESS 5 */
|
||||||
|
/* B_RANDOMIZED_ANY_ADDRESS 6 */
|
||||||
|
#define B_RANDOMIZED_BASE_ADDRESS 7
|
||||||
|
|
||||||
/* area protection */
|
/* area protection */
|
||||||
#define B_READ_AREA 1
|
#define B_READ_AREA 1
|
||||||
|
|||||||
@@ -29,6 +29,15 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef B_HAIKU_64_BIT
|
||||||
|
const addr_t VMUserAddressSpace::kMaxRandomize = 0x8000000000ul;
|
||||||
|
const addr_t VMUserAddressSpace::kMaxInitialRandomize = 0x20000000000ul;
|
||||||
|
#else
|
||||||
|
const addr_t VMUserAddressSpace::kMaxRandomize = 0x800000ul;
|
||||||
|
const addr_t VMUserAddressSpace::kMaxInitialRandomize = 0x2000000ul;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*! Verifies that an area with the given aligned base and size fits into
|
/*! Verifies that an area with the given aligned base and size fits into
|
||||||
the spot defined by base and limit and checks for overflows.
|
the spot defined by base and limit and checks for overflows.
|
||||||
*/
|
*/
|
||||||
@@ -40,6 +49,26 @@ is_valid_spot(addr_t base, addr_t alignedBase, addr_t size, addr_t limit)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* http://graphics.stanford.edu/~seander/bithacks.html */
|
||||||
|
static inline int
|
||||||
|
log2(uint32_t v)
|
||||||
|
{
|
||||||
|
static const int multiply_debruijn_bit_position[32] =
|
||||||
|
{
|
||||||
|
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
|
||||||
|
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
|
||||||
|
};
|
||||||
|
|
||||||
|
v |= v >> 1;
|
||||||
|
v |= v >> 2;
|
||||||
|
v |= v >> 4;
|
||||||
|
v |= v >> 8;
|
||||||
|
v |= v >> 16;
|
||||||
|
|
||||||
|
return multiply_debruijn_bit_position[(uint32_t)(v * 0x07c4acddu) >> 27];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
VMUserAddressSpace::VMUserAddressSpace(team_id id, addr_t base, size_t size)
|
VMUserAddressSpace::VMUserAddressSpace(team_id id, addr_t base, size_t size)
|
||||||
:
|
:
|
||||||
VMAddressSpace(id, base, size, "address space"),
|
VMAddressSpace(id, base, size, "address space"),
|
||||||
@@ -137,6 +166,7 @@ VMUserAddressSpace::InsertArea(VMArea* _area, size_t size,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case B_BASE_ADDRESS:
|
case B_BASE_ADDRESS:
|
||||||
|
case B_RANDOMIZED_BASE_ADDRESS:
|
||||||
searchBase = (addr_t)addressRestrictions->address;
|
searchBase = (addr_t)addressRestrictions->address;
|
||||||
searchEnd = fEndAddress;
|
searchEnd = fEndAddress;
|
||||||
break;
|
break;
|
||||||
@@ -371,6 +401,41 @@ VMUserAddressSpace::Dump() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
addr_t
|
||||||
|
VMUserAddressSpace::_RandomizeAddress(addr_t start, addr_t end, bool initial)
|
||||||
|
{
|
||||||
|
if (start == end)
|
||||||
|
return start;
|
||||||
|
|
||||||
|
const int kRandShift = log2(RAND_MAX) + 1;
|
||||||
|
int shift = 0;
|
||||||
|
#ifdef B_HAIKU_64_BIT
|
||||||
|
uint64_t random = 0;
|
||||||
|
while (shift < 64) {
|
||||||
|
random |= (uint64_t)rand() << shift;
|
||||||
|
shift += kRandShift;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
uint32_t random = 0;
|
||||||
|
while (shift < 32) {
|
||||||
|
random |= (uint32_t)rand() << shift;
|
||||||
|
shift += kRandShift;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
addr_t range = end - start;
|
||||||
|
if (initial)
|
||||||
|
range = min_c(range, kMaxInitialRandomize);
|
||||||
|
else
|
||||||
|
range = min_c(range, kMaxRandomize);
|
||||||
|
|
||||||
|
random %= range;
|
||||||
|
random &= ~addr_t(B_PAGE_SIZE - 1);
|
||||||
|
|
||||||
|
return start + random;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Finds a reserved area that covers the region spanned by \a start and
|
/*! Finds a reserved area that covers the region spanned by \a start and
|
||||||
\a size, inserts the \a area into that region and makes sure that
|
\a size, inserts the \a area into that region and makes sure that
|
||||||
there are reserved regions for the remaining parts.
|
there are reserved regions for the remaining parts.
|
||||||
@@ -459,6 +524,7 @@ VMUserAddressSpace::_InsertAreaSlot(addr_t start, addr_t size, addr_t end,
|
|||||||
VMUserArea* last = NULL;
|
VMUserArea* last = NULL;
|
||||||
VMUserArea* next;
|
VMUserArea* next;
|
||||||
bool foundSpot = false;
|
bool foundSpot = false;
|
||||||
|
addr_t originalStart = 0;
|
||||||
|
|
||||||
TRACE(("VMUserAddressSpace::_InsertAreaSlot: address space %p, start "
|
TRACE(("VMUserAddressSpace::_InsertAreaSlot: address space %p, start "
|
||||||
"0x%lx, size %ld, end 0x%lx, addressSpec %" B_PRIu32 ", area %p\n",
|
"0x%lx, size %ld, end 0x%lx, addressSpec %" B_PRIu32 ", area %p\n",
|
||||||
@@ -489,6 +555,11 @@ VMUserAddressSpace::_InsertAreaSlot(addr_t start, addr_t size, addr_t end,
|
|||||||
alignment <<= 1;
|
alignment <<= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addressSpec == B_RANDOMIZED_BASE_ADDRESS) {
|
||||||
|
originalStart = start;
|
||||||
|
start = _RandomizeAddress(start, end - size, true);
|
||||||
|
}
|
||||||
|
|
||||||
start = ROUNDUP(start, alignment);
|
start = ROUNDUP(start, alignment);
|
||||||
|
|
||||||
// walk up to the spot where we should start searching
|
// walk up to the spot where we should start searching
|
||||||
@@ -614,6 +685,7 @@ second_chance:
|
|||||||
}
|
}
|
||||||
|
|
||||||
case B_BASE_ADDRESS:
|
case B_BASE_ADDRESS:
|
||||||
|
case B_RANDOMIZED_BASE_ADDRESS:
|
||||||
{
|
{
|
||||||
// find a hole big enough for a new area beginning with "start"
|
// find a hole big enough for a new area beginning with "start"
|
||||||
if (last == NULL) {
|
if (last == NULL) {
|
||||||
@@ -646,15 +718,33 @@ second_chance:
|
|||||||
foundSpot = true;
|
foundSpot = true;
|
||||||
if (lastEnd < start)
|
if (lastEnd < start)
|
||||||
area->SetBase(start);
|
area->SetBase(start);
|
||||||
else
|
else {
|
||||||
area->SetBase(lastEnd + 1);
|
start = lastEnd + 1;
|
||||||
|
if (addressSpec == B_RANDOMIZED_BASE_ADDRESS) {
|
||||||
|
addr_t spaceEnd = end;
|
||||||
|
if (next != NULL)
|
||||||
|
spaceEnd = next->Base();
|
||||||
|
|
||||||
|
start = _RandomizeAddress(lastEnd + 1, spaceEnd - size,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
area->SetBase(start);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we didn't find a free spot in the requested range, so we'll
|
// we didn't find a free spot in the requested range, so we'll
|
||||||
// try again without any restrictions
|
// try again without any restrictions
|
||||||
start = fBase;
|
if (addressSpec != B_RANDOMIZED_BASE_ADDRESS
|
||||||
addressSpec = B_ANY_ADDRESS;
|
|| originalStart == 0) {
|
||||||
|
start = fBase;
|
||||||
|
addressSpec = B_ANY_ADDRESS;
|
||||||
|
} else {
|
||||||
|
start = originalStart;
|
||||||
|
originalStart = 0;
|
||||||
|
}
|
||||||
|
|
||||||
last = NULL;
|
last = NULL;
|
||||||
goto second_chance;
|
goto second_chance;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ public:
|
|||||||
virtual void Dump() const;
|
virtual void Dump() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static addr_t _RandomizeAddress(addr_t start, addr_t end,
|
||||||
|
bool initial);
|
||||||
|
|
||||||
status_t _InsertAreaIntoReservedRegion(addr_t start,
|
status_t _InsertAreaIntoReservedRegion(addr_t start,
|
||||||
size_t size, VMUserArea* area,
|
size_t size, VMUserArea* area,
|
||||||
uint32 allocationFlags);
|
uint32 allocationFlags);
|
||||||
@@ -62,6 +65,9 @@ private:
|
|||||||
uint32 allocationFlags);
|
uint32 allocationFlags);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static const addr_t kMaxRandomize;
|
||||||
|
static const addr_t kMaxInitialRandomize;
|
||||||
|
|
||||||
VMUserAreaList fAreas;
|
VMUserAreaList fAreas;
|
||||||
mutable VMUserArea* fAreaHint;
|
mutable VMUserArea* fAreaHint;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1219,6 +1219,7 @@ vm_create_anonymous_area(team_id team, const char *name, addr_t size,
|
|||||||
case B_BASE_ADDRESS:
|
case B_BASE_ADDRESS:
|
||||||
case B_ANY_KERNEL_ADDRESS:
|
case B_ANY_KERNEL_ADDRESS:
|
||||||
case B_ANY_KERNEL_BLOCK_ADDRESS:
|
case B_ANY_KERNEL_BLOCK_ADDRESS:
|
||||||
|
case B_RANDOMIZED_BASE_ADDRESS:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user