* 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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user