* 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); status_t _user_set_area_protection(area_id area, uint32 newProtection);
area_id _user_clone_area(const char *name, void **_address, uint32 addressSpec, area_id _user_clone_area(const char *name, void **_address, uint32 addressSpec,
uint32 protection, area_id sourceArea); 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); addr_t size);
status_t _user_unreserve_address_range(addr_t address, addr_t size);
#ifdef __cplusplus #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, extern area_id _kern_clone_area(const char *name, void **_address,
uint32 addressSpec, uint32 protection, uint32 addressSpec, uint32 protection,
area_id sourceArea); 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); 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, extern area_id _kern_map_file(const char *name, void **address,
int addressSpec, size_t size, int protection, 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. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
* Axel Dörfler, [email protected] * 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 supposed to have a BPrivate::AppServerLink object around which
does the necessary locking. does the necessary locking.
However, this is not enforced in the methods here, you have to 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) { if (!readOnly) {
// reserve 128 MB of space for the area // reserve 128 MB of space for the area
base = (void*)0x60000000; base = (void*)0x60000000;
status = _kern_reserve_heap_address_range((addr_t*)&base, status = _kern_reserve_address_range((addr_t*)&base, B_BASE_ADDRESS,
B_BASE_ADDRESS, 128 * 1024 * 1024); 128 * 1024 * 1024);
addressSpec = status == B_OK ? B_EXACT_ADDRESS : B_BASE_ADDRESS; addressSpec = status == B_OK ? B_EXACT_ADDRESS : B_BASE_ADDRESS;
} }
#endif #endif
mapping->local_area = clone_area(readOnly ? "server read-only memory" : "server_memory", mapping->local_area = clone_area(readOnly
&base, addressSpec, B_READ_AREA | (readOnly ? 0 : B_WRITE_AREA), serverArea); ? "server read-only memory" : "server_memory",
&base, addressSpec,
B_READ_AREA | (readOnly ? 0 : B_WRITE_AREA), serverArea);
if (mapping->local_area < B_OK) { if (mapping->local_area < B_OK) {
status = mapping->local_area; status = mapping->local_area;
@@ -118,7 +119,8 @@ ServerMemoryAllocator::RemoveArea(area_id serverArea)
status_t 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;) { for (int32 i = fAreas.CountItems(); i-- > 0;) {
area_mapping* mapping = (area_mapping*)fAreas.ItemAt(i); 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); status = insert_area(addressSpace, _virtualAddress, addressSpec, size, area);
if (status < B_OK) if (status != B_OK)
goto err2; goto err2;
// attach the cache to the area // 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, status_t status = insert_area(locker.AddressSpace(), _address, addressSpec,
size, area); size, area);
if (status < B_OK) { if (status != B_OK) {
free(area); free(area);
return status; return status;
} }
@@ -5907,8 +5907,7 @@ delete_area(area_id area)
status_t status_t
_user_reserve_heap_address_range(addr_t* userAddress, uint32 addressSpec, _user_reserve_address_range(addr_t* userAddress, uint32 addressSpec, addr_t size)
addr_t size)
{ {
// filter out some unavailable values (for userland) // filter out some unavailable values (for userland)
switch (addressSpec) { switch (addressSpec) {
@@ -5920,16 +5919,16 @@ _user_reserve_heap_address_range(addr_t* userAddress, uint32 addressSpec,
addr_t address; addr_t address;
if (!IS_USER_ADDRESS(userAddress) 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; return B_BAD_ADDRESS;
status_t status = vm_reserve_address_range( status_t status = vm_reserve_address_range(
vm_current_user_address_space_id(), (void**)&address, addressSpec, size, vm_current_user_address_space_id(), (void**)&address, addressSpec, size,
RESERVED_AVOID_BASE); RESERVED_AVOID_BASE);
if (status < B_OK) if (status != B_OK)
return status; 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(), vm_unreserve_address_range(vm_current_user_address_space_id(),
(void*)address, size); (void*)address, size);
return B_BAD_ADDRESS; 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 area_id
_user_area_for(void* address) _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 // 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. // size of the heap is guaranteed until the space is really needed.
sHeapBase = (void *)0x18000000; 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); B_EXACT_ADDRESS, 0x48000000);
sHeapArea = create_area("heap", (void **)&sHeapBase, 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 - // #pragma mark -
@@ -260,74 +284,95 @@ map_image(int fd, char const* path, image_t* image, bool fixed)
else else
baseName = path; baseName = path;
for (uint32 i = 0; i < image->num_regions; i++) { // determine how much space we need for all loaded segments
char regionName[B_OS_NAME_LENGTH];
addr_t loadAddress;
uint32 addressSpecifier;
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 // for BeOS compatibility: if we load an old BeOS executable, we
// have to relocate it, if possible - we recognize it because the // have to relocate it, if possible - we recognize it because the
// vmstart is set to 0 (hopefully always) // vmstart is set to 0 (hopefully always)
if (fixed && image->regions[i].vmstart == 0) if (fixed && image->regions[i].vmstart == 0)
fixed = false; 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", snprintf(regionName, sizeof(regionName), "%s_seg%lu%s",
baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro"); baseName, i, (image->regions[i].flags & RFLAG_RW) ? "rw" : "ro");
if (image->dynamic_ptr && !fixed) { get_image_region_load_address(image, i, image->regions[i - 1].delta,
// relocatable image... we can afford to place wherever fixed, loadAddress, addressSpecifier);
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;
}
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, image->regions[i].id = _kern_create_area(regionName,
(void**)&loadAddress, addressSpecifier, (void**)&loadAddress, B_EXACT_ADDRESS,
image->regions[i].vmsize, B_NO_LOCK, image->regions[i].vmsize, B_NO_LOCK,
B_READ_AREA | B_WRITE_AREA); 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; return image->regions[i].id;
}
image->regions[i].delta = loadAddress - image->regions[i].vmstart;
image->regions[i].vmstart = loadAddress;
} else { } else {
image->regions[i].id = _kern_map_file(regionName, 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, image->regions[i].vmsize, B_READ_AREA | B_WRITE_AREA,
REGION_PRIVATE_MAP, false, fd, REGION_PRIVATE_MAP, false, fd,
PAGE_BASE(image->regions[i].fdstart)); 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; return image->regions[i].id;
}
TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path, TRACE(("\"%s\" at %p, 0x%lx bytes (%s)\n", path,
(void *)loadAddress, image->regions[i].vmsize, (void *)loadAddress, image->regions[i].vmsize,
image->regions[i].flags & RFLAG_RW ? "rw" : "read-only")); 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 // handle trailer bits in data segment
if (image->regions[i].flags & RFLAG_RW) { if (image->regions[i].flags & RFLAG_RW) {
addr_t startClearing; addr_t startClearing = loadAddress
addr_t toClear;
startClearing = image->regions[i].vmstart
+ PAGE_OFFSET(image->regions[i].start) + PAGE_OFFSET(image->regions[i].start)
+ image->regions[i].size; + image->regions[i].size;
toClear = image->regions[i].vmsize addr_t toClear = image->regions[i].vmsize
- PAGE_OFFSET(image->regions[i].start) - PAGE_OFFSET(image->regions[i].start)
- image->regions[i].size; - 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); 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; image->dynamic_ptr += image->regions[0].delta;
return B_OK; return B_OK;