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