* Renamed _kern_reserve_heap_address_range() to _kern_reserve_address_range(),

and added a _kern_unreserve_address_range() as well.
* The runtime loader now reserves the space needed for all its areas first
  to make sure there is enough space left for all areas of a single image.
* This also fixes the final part of bug #4008.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31115 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-06-19 11:09:21 +00:00
parent 7200c6f499
commit 3609af391d
6 changed files with 114 additions and 55 deletions
+2 -1
View File
@@ -139,8 +139,9 @@ area_id _user_transfer_area(area_id area, void **_address, uint32 addressSpec,
status_t _user_set_area_protection(area_id area, uint32 newProtection);
area_id _user_clone_area(const char *name, void **_address, uint32 addressSpec,
uint32 protection, area_id sourceArea);
status_t _user_reserve_heap_address_range(addr_t* userAddress, uint32 addressSpec,
status_t _user_reserve_address_range(addr_t* userAddress, uint32 addressSpec,
addr_t size);
status_t _user_unreserve_address_range(addr_t address, addr_t size);
#ifdef __cplusplus
}
+2 -1
View File
@@ -373,8 +373,9 @@ extern status_t _kern_set_area_protection(area_id area,
extern area_id _kern_clone_area(const char *name, void **_address,
uint32 addressSpec, uint32 protection,
area_id sourceArea);
extern status_t _kern_reserve_heap_address_range(addr_t* _address,
extern status_t _kern_reserve_address_range(addr_t* _address,
uint32 addressSpec, addr_t size);
extern status_t _kern_unreserve_address_range(addr_t address, addr_t size);
extern area_id _kern_map_file(const char *name, void **address,
int addressSpec, size_t size, int protection,
+10 -8
View File
@@ -1,13 +1,12 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, [email protected]
*/
/*!
Note, this class don't provide any locking whatsoever - you are
/*! Note, this class don't provide any locking whatsoever - you are
supposed to have a BPrivate::AppServerLink object around which
does the necessary locking.
However, this is not enforced in the methods here, you have to
@@ -74,14 +73,16 @@ ServerMemoryAllocator::AddArea(area_id serverArea, area_id& _area, uint8*& _base
if (!readOnly) {
// reserve 128 MB of space for the area
base = (void*)0x60000000;
status = _kern_reserve_heap_address_range((addr_t*)&base,
B_BASE_ADDRESS, 128 * 1024 * 1024);
status = _kern_reserve_address_range((addr_t*)&base, B_BASE_ADDRESS,
128 * 1024 * 1024);
addressSpec = status == B_OK ? B_EXACT_ADDRESS : B_BASE_ADDRESS;
}
#endif
mapping->local_area = clone_area(readOnly ? "server read-only memory" : "server_memory",
&base, addressSpec, B_READ_AREA | (readOnly ? 0 : B_WRITE_AREA), serverArea);
mapping->local_area = clone_area(readOnly
? "server read-only memory" : "server_memory",
&base, addressSpec,
B_READ_AREA | (readOnly ? 0 : B_WRITE_AREA), serverArea);
if (mapping->local_area < B_OK) {
status = mapping->local_area;
@@ -118,7 +119,8 @@ ServerMemoryAllocator::RemoveArea(area_id serverArea)
status_t
ServerMemoryAllocator::AreaAndBaseFor(area_id serverArea, area_id& _area, uint8*& _base)
ServerMemoryAllocator::AreaAndBaseFor(area_id serverArea, area_id& _area,
uint8*& _base)
{
for (int32 i = fAreas.CountItems(); i-- > 0;) {
area_mapping* mapping = (area_mapping*)fAreas.ItemAt(i);
+14 -7
View File
@@ -1632,7 +1632,7 @@ map_backing_store(vm_address_space* addressSpace, vm_cache* cache,
}
status = insert_area(addressSpace, _virtualAddress, addressSpec, size, area);
if (status < B_OK)
if (status != B_OK)
goto err2;
// attach the cache to the area
@@ -1741,7 +1741,7 @@ vm_reserve_address_range(team_id team, void** _address, uint32 addressSpec,
status_t status = insert_area(locker.AddressSpace(), _address, addressSpec,
size, area);
if (status < B_OK) {
if (status != B_OK) {
free(area);
return status;
}
@@ -5907,8 +5907,7 @@ delete_area(area_id area)
status_t
_user_reserve_heap_address_range(addr_t* userAddress, uint32 addressSpec,
addr_t size)
_user_reserve_address_range(addr_t* userAddress, uint32 addressSpec, addr_t size)
{
// filter out some unavailable values (for userland)
switch (addressSpec) {
@@ -5920,16 +5919,16 @@ _user_reserve_heap_address_range(addr_t* userAddress, uint32 addressSpec,
addr_t address;
if (!IS_USER_ADDRESS(userAddress)
|| user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
|| user_memcpy(&address, userAddress, sizeof(address)) != B_OK)
return B_BAD_ADDRESS;
status_t status = vm_reserve_address_range(
vm_current_user_address_space_id(), (void**)&address, addressSpec, size,
RESERVED_AVOID_BASE);
if (status < B_OK)
if (status != B_OK)
return status;
if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK) {
if (user_memcpy(userAddress, &address, sizeof(address)) != B_OK) {
vm_unreserve_address_range(vm_current_user_address_space_id(),
(void*)address, size);
return B_BAD_ADDRESS;
@@ -5939,6 +5938,14 @@ _user_reserve_heap_address_range(addr_t* userAddress, uint32 addressSpec,
}
status_t
_user_unreserve_address_range(addr_t address, addr_t size)
{
return vm_unreserve_address_range(vm_current_user_address_space_id(),
(void*)address, size);
}
area_id
_user_area_for(void* address)
{
@@ -88,7 +88,7 @@ __init_heap(void)
// for it. They may get reclaimed by other areas, though, but the maximum
// size of the heap is guaranteed until the space is really needed.
sHeapBase = (void *)0x18000000;
status_t status = _kern_reserve_heap_address_range((addr_t *)&sHeapBase,
status_t status = _kern_reserve_address_range((addr_t *)&sHeapBase,
B_EXACT_ADDRESS, 0x48000000);
sHeapArea = create_area("heap", (void **)&sHeapBase,
+85 -37
View File
@@ -154,6 +154,30 @@ topological_sort(image_t* image, uint32 slot, image_t** initList,
}
/*! Finds the load address and address specifier of the given image region.
*/
static void
get_image_region_load_address(image_t* image, uint32 index, int32 lastDelta,
bool fixed, addr_t& loadAddress, uint32& addressSpecifier)
{
if (image->dynamic_ptr != 0 && !fixed) {
// relocatable image... we can afford to place wherever
if (index == 0) {
// but only the first segment gets a free ride
loadAddress = RLD_PROGRAM_BASE;
addressSpecifier = B_BASE_ADDRESS;
} else {
loadAddress = image->regions[index].vmstart + lastDelta;
addressSpecifier = B_EXACT_ADDRESS;
}
} else {
// not relocatable, put it where it asks or die trying
loadAddress = image->regions[index].vmstart;
addressSpecifier = B_EXACT_ADDRESS;
}
}
// #pragma mark -
@@ -260,74 +284,95 @@ map_image(int fd, char const* path, image_t* image, bool fixed)
else
baseName = path;
for (uint32 i = 0; i < image->num_regions; i++) {
char regionName[B_OS_NAME_LENGTH];
addr_t loadAddress;
uint32 addressSpecifier;
// determine how much space we need for all loaded segments
addr_t reservedAddress = 0;
addr_t loadAddress;
size_t reservedSize = 0;
size_t length = 0;
uint32 addressSpecifier = B_ANY_ADDRESS;
for (uint32 i = 0; i < image->num_regions; i++) {
// for BeOS compatibility: if we load an old BeOS executable, we
// have to relocate it, if possible - we recognize it because the
// vmstart is set to 0 (hopefully always)
if (fixed && image->regions[i].vmstart == 0)
fixed = false;
uint32 regionAddressSpecifier;
get_image_region_load_address(image, i,
loadAddress - image->regions[i - 1].vmstart, fixed,
loadAddress, regionAddressSpecifier);
if (i == 0) {
reservedAddress = loadAddress;
addressSpecifier = regionAddressSpecifier;
}
length += TO_PAGE_SIZE(image->regions[i].vmsize
+ (loadAddress % B_PAGE_SIZE));
size_t size = TO_PAGE_SIZE(loadAddress + image->regions[i].vmsize)
- reservedAddress;
if (size > reservedSize)
reservedSize = size;
}
// Check whether the segments have an unreasonable amount of unused space
// inbetween.
if (reservedSize > length + 8 * 1024)
return B_BAD_DATA;
// reserve that space and allocate the areas from that one
if (_kern_reserve_address_range(&reservedAddress, addressSpecifier,
reservedSize) != B_OK)
return B_NO_MEMORY;
for (uint32 i = 0; i < image->num_regions; i++) {
char regionName[B_OS_NAME_LENGTH];
snprintf(regionName, sizeof(regionName), "%s_seg%lu%s",
baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro");
if (image->dynamic_ptr && !fixed) {
// relocatable image... we can afford to place wherever
if (i == 0) {
// but only the first segment gets a free ride
loadAddress = RLD_PROGRAM_BASE;
addressSpecifier = B_BASE_ADDRESS;
} else {
loadAddress = image->regions[i].vmstart
+ image->regions[i-1].delta;
addressSpecifier = B_EXACT_ADDRESS;
}
} else {
// not relocatable, put it where it asks or die trying
loadAddress = image->regions[i].vmstart;
addressSpecifier = B_EXACT_ADDRESS;
}
get_image_region_load_address(image, i, image->regions[i - 1].delta,
fixed, loadAddress, addressSpecifier);
if (image->regions[i].flags & RFLAG_ANON) {
// If the image position is arbitrary, we must let it point to the start
// of the reserved address range.
if (addressSpecifier != B_EXACT_ADDRESS)
loadAddress = reservedAddress;
if ((image->regions[i].flags & RFLAG_ANON) != 0) {
image->regions[i].id = _kern_create_area(regionName,
(void**)&loadAddress, addressSpecifier,
(void**)&loadAddress, B_EXACT_ADDRESS,
image->regions[i].vmsize, B_NO_LOCK,
B_READ_AREA | B_WRITE_AREA);
if (image->regions[i].id < 0)
if (image->regions[i].id < 0) {
_kern_unreserve_address_range(reservedAddress, reservedSize);
return image->regions[i].id;
image->regions[i].delta = loadAddress - image->regions[i].vmstart;
image->regions[i].vmstart = loadAddress;
}
} else {
image->regions[i].id = _kern_map_file(regionName,
(void**)&loadAddress, addressSpecifier,
(void**)&loadAddress, B_EXACT_ADDRESS,
image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA,
REGION_PRIVATE_MAP, false, fd,
PAGE_BASE(image->regions[i].fdstart));
if (image->regions[i].id < 0)
if (image->regions[i].id < 0) {
_kern_unreserve_address_range(reservedAddress, reservedSize);
return image->regions[i].id;
}
TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path,
(void *)loadAddress, image->regions[i].vmsize,
image->regions[i].flags & RFLAG_RW ? "rw" : "read-only"));
image->regions[i].delta = loadAddress - image->regions[i].vmstart;
image->regions[i].vmstart = loadAddress;
// handle trailer bits in data segment
if (image->regions[i].flags & RFLAG_RW) {
addr_t startClearing;
addr_t toClear;
startClearing = image->regions[i].vmstart
addr_t startClearing = loadAddress
+ PAGE_OFFSET(image->regions[i].start)
+ image->regions[i].size;
toClear = image->regions[i].vmsize
addr_t toClear = image->regions[i].vmsize
- PAGE_OFFSET(image->regions[i].start)
- image->regions[i].size;
@@ -336,9 +381,12 @@ map_image(int fd, char const* path, image_t* image, bool fixed)
memset((void *)startClearing, 0, toClear);
}
}
image->regions[i].delta = loadAddress - image->regions[i].vmstart;
image->regions[i].vmstart = loadAddress;
}
if (image->dynamic_ptr)
if (image->dynamic_ptr != 0)
image->dynamic_ptr += image->regions[0].delta;
return B_OK;