* Changed the address space area list to doubly linked. The reason is to
simplify migration of the area management, but as a side effect, it also
makes area deletion O(1) (instead of O(n), n == number of areas in the
address space).
* Moved more area management functionality from vm.cpp to VMAddressSpace and
VMArea structure creation to VMArea. Made the list and list link members
itself private.
* VMAddressSpace tracks its amount of free space, now. This also replaces
the previous mechanism to do that only for the kernel address space. It
was broken anyway, since delete_area() subtracted the area size instead of
adding it.
* vm_free_unused_boot_loader_range():
- lastEnd could be set to a value < start, which could cause memory
outside of the given range to be unmapped. Haven't checked whether this
could happen in practice -- if so, it would be seriously unhealthy.
- The range between the end of the last area in the range and the end of
the range would never be freed.
- Fixed potential integer overflows when computing addresses.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34459 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -13,12 +13,14 @@
|
|||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
|
|
||||||
#include <vm/vm_translation_map.h>
|
#include <vm/vm_translation_map.h>
|
||||||
|
#include <vm/VMArea.h>
|
||||||
|
|
||||||
struct VMArea;
|
|
||||||
|
|
||||||
|
|
||||||
struct VMAddressSpace {
|
struct VMAddressSpace {
|
||||||
|
public:
|
||||||
|
class Iterator;
|
||||||
|
|
||||||
|
public:
|
||||||
VMAddressSpace(team_id id, addr_t base,
|
VMAddressSpace(team_id id, addr_t base,
|
||||||
size_t size, bool kernel);
|
size_t size, bool kernel);
|
||||||
~VMAddressSpace();
|
~VMAddressSpace();
|
||||||
@@ -29,6 +31,7 @@ struct VMAddressSpace {
|
|||||||
team_id ID() const { return fID; }
|
team_id ID() const { return fID; }
|
||||||
addr_t Base() const { return fBase; }
|
addr_t Base() const { return fBase; }
|
||||||
size_t Size() const { return fSize; }
|
size_t Size() const { return fSize; }
|
||||||
|
size_t FreeSpace() const { return fFreeSpace; }
|
||||||
bool IsBeingDeleted() const { return fDeleting; }
|
bool IsBeingDeleted() const { return fDeleting; }
|
||||||
|
|
||||||
vm_translation_map& TranslationMap() { return fTranslationMap; }
|
vm_translation_map& TranslationMap() { return fTranslationMap; }
|
||||||
@@ -54,9 +57,18 @@ struct VMAddressSpace {
|
|||||||
void IncrementChangeCount()
|
void IncrementChangeCount()
|
||||||
{ fChangeCount++; }
|
{ fChangeCount++; }
|
||||||
|
|
||||||
VMArea* LookupArea(addr_t address);
|
VMArea* FirstArea() const
|
||||||
|
{ return fAreas.Head(); }
|
||||||
|
VMArea* NextArea(VMArea* area) const
|
||||||
|
{ return fAreas.GetNext(area); }
|
||||||
|
|
||||||
|
VMArea* LookupArea(addr_t address) const;
|
||||||
|
status_t InsertArea(void** _address, uint32 addressSpec,
|
||||||
|
addr_t size, VMArea* area);
|
||||||
void RemoveArea(VMArea* area);
|
void RemoveArea(VMArea* area);
|
||||||
|
|
||||||
|
inline Iterator GetIterator();
|
||||||
|
|
||||||
static status_t Create(team_id teamID, addr_t base, size_t size,
|
static status_t Create(team_id teamID, addr_t base, size_t size,
|
||||||
bool kernel,
|
bool kernel,
|
||||||
VMAddressSpace** _addressSpace);
|
VMAddressSpace** _addressSpace);
|
||||||
@@ -77,31 +89,76 @@ struct VMAddressSpace {
|
|||||||
void Dump() const;
|
void Dump() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
status_t _InsertAreaIntoReservedRegion(addr_t start,
|
||||||
|
size_t size, VMArea* area);
|
||||||
|
status_t _InsertAreaSlot(addr_t start, addr_t size,
|
||||||
|
addr_t end, uint32 addressSpec,
|
||||||
|
VMArea* area);
|
||||||
|
|
||||||
static int _DumpCommand(int argc, char** argv);
|
static int _DumpCommand(int argc, char** argv);
|
||||||
static int _DumpListCommand(int argc, char** argv);
|
static int _DumpListCommand(int argc, char** argv);
|
||||||
|
|
||||||
public:
|
|
||||||
VMArea* areas;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class Iterator;
|
||||||
|
|
||||||
struct HashDefinition;
|
struct HashDefinition;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VMAddressSpace* fHashTableLink;
|
VMAddressSpace* fHashTableLink;
|
||||||
addr_t fBase;
|
addr_t fBase;
|
||||||
size_t fSize;
|
size_t fSize;
|
||||||
|
size_t fFreeSpace;
|
||||||
rw_lock fLock;
|
rw_lock fLock;
|
||||||
team_id fID;
|
team_id fID;
|
||||||
int32 fRefCount;
|
int32 fRefCount;
|
||||||
int32 fFaultCount;
|
int32 fFaultCount;
|
||||||
int32 fChangeCount;
|
int32 fChangeCount;
|
||||||
vm_translation_map fTranslationMap;
|
vm_translation_map fTranslationMap;
|
||||||
VMArea* fAreaHint;
|
VMAddressSpaceAreaList fAreas;
|
||||||
|
mutable VMArea* fAreaHint;
|
||||||
bool fDeleting;
|
bool fDeleting;
|
||||||
static VMAddressSpace* sKernelAddressSpace;
|
static VMAddressSpace* sKernelAddressSpace;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class VMAddressSpace::Iterator {
|
||||||
|
public:
|
||||||
|
Iterator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator(VMAddressSpace* addressSpace)
|
||||||
|
:
|
||||||
|
fIterator(addressSpace->fAreas.GetIterator())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasNext() const
|
||||||
|
{
|
||||||
|
return fIterator.HasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
VMArea* Next()
|
||||||
|
{
|
||||||
|
return fIterator.Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rewind()
|
||||||
|
{
|
||||||
|
fIterator.Rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
VMAddressSpaceAreaList::Iterator fIterator;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline VMAddressSpace::Iterator
|
||||||
|
VMAddressSpace::GetIterator()
|
||||||
|
{
|
||||||
|
return Iterator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <lock.h>
|
#include <lock.h>
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
#include <util/OpenHashTable.h>
|
#include <util/OpenHashTable.h>
|
||||||
#include <vm/vm_types.h>
|
#include <vm/vm_types.h>
|
||||||
|
|
||||||
@@ -36,16 +37,47 @@ struct VMArea {
|
|||||||
uint8* page_protections;
|
uint8* page_protections;
|
||||||
|
|
||||||
struct VMAddressSpace* address_space;
|
struct VMAddressSpace* address_space;
|
||||||
struct VMArea* address_space_next;
|
|
||||||
struct VMArea* cache_next;
|
struct VMArea* cache_next;
|
||||||
struct VMArea* cache_prev;
|
struct VMArea* cache_prev;
|
||||||
struct VMArea* hash_next;
|
struct VMArea* hash_next;
|
||||||
|
|
||||||
bool ContainsAddress(addr_t address) const
|
bool ContainsAddress(addr_t address) const
|
||||||
{ return address >= base && address <= base + (size - 1); }
|
{ return address >= base
|
||||||
|
&& address <= base + (size - 1); }
|
||||||
|
|
||||||
|
static VMArea* Create(VMAddressSpace* addressSpace,
|
||||||
|
const char* name, uint32 wiring,
|
||||||
|
uint32 protection);
|
||||||
|
static VMArea* CreateReserved(VMAddressSpace* addressSpace,
|
||||||
|
uint32 flags);
|
||||||
|
|
||||||
|
DoublyLinkedListLink<VMArea>& AddressSpaceLink()
|
||||||
|
{ return fAddressSpaceLink; }
|
||||||
|
const DoublyLinkedListLink<VMArea>& AddressSpaceLink() const
|
||||||
|
{ return fAddressSpaceLink; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
DoublyLinkedListLink<VMArea> fAddressSpaceLink;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct VMAddressSpaceAreaGetLink {
|
||||||
|
inline DoublyLinkedListLink<VMArea>* operator()(VMArea* area) const
|
||||||
|
{
|
||||||
|
return &area->AddressSpaceLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const DoublyLinkedListLink<VMArea>* operator()(
|
||||||
|
const VMArea* area) const
|
||||||
|
{
|
||||||
|
return &area->AddressSpaceLink();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef DoublyLinkedList<VMArea, VMAddressSpaceAreaGetLink>
|
||||||
|
VMAddressSpaceAreaList;
|
||||||
|
|
||||||
|
|
||||||
struct VMAreaHashDefinition {
|
struct VMAreaHashDefinition {
|
||||||
typedef area_id KeyType;
|
typedef area_id KeyType;
|
||||||
typedef VMArea ValueType;
|
typedef VMArea ValueType;
|
||||||
|
|||||||
@@ -1303,11 +1303,11 @@ public:
|
|||||||
status_t Init(struct team* team)
|
status_t Init(struct team* team)
|
||||||
{
|
{
|
||||||
// find the runtime loader debug area
|
// find the runtime loader debug area
|
||||||
VMArea* area = team->address_space->areas;
|
VMArea* area;
|
||||||
while (area != NULL) {
|
for (VMAddressSpace::Iterator it = team->address_space->GetIterator();
|
||||||
|
(area = it.Next()) != NULL;) {
|
||||||
if (strcmp(area->name, RUNTIME_LOADER_DEBUG_AREA_NAME) == 0)
|
if (strcmp(area->name, RUNTIME_LOADER_DEBUG_AREA_NAME) == 0)
|
||||||
break;
|
break;
|
||||||
area = area->address_space_next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (area == NULL)
|
if (area == NULL)
|
||||||
|
|||||||
@@ -34,6 +34,17 @@
|
|||||||
#define ASPACE_HASH_TABLE_SIZE 1024
|
#define ASPACE_HASH_TABLE_SIZE 1024
|
||||||
|
|
||||||
|
|
||||||
|
/*! Verifies that an area with the given aligned base and size fits into
|
||||||
|
the spot defined by base and limit and checks for overflows.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
is_valid_spot(addr_t base, addr_t alignedBase, addr_t size, addr_t limit)
|
||||||
|
{
|
||||||
|
return (alignedBase >= base && alignedBase + (size - 1) > alignedBase
|
||||||
|
&& alignedBase + (size - 1) <= limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - AddressSpaceHashDefinition
|
// #pragma mark - AddressSpaceHashDefinition
|
||||||
|
|
||||||
|
|
||||||
@@ -76,10 +87,9 @@ VMAddressSpace* VMAddressSpace::sKernelAddressSpace;
|
|||||||
VMAddressSpace::VMAddressSpace(team_id id, addr_t base, size_t size,
|
VMAddressSpace::VMAddressSpace(team_id id, addr_t base, size_t size,
|
||||||
bool kernel)
|
bool kernel)
|
||||||
:
|
:
|
||||||
areas(NULL),
|
|
||||||
|
|
||||||
fBase(base),
|
fBase(base),
|
||||||
fSize(size),
|
fSize(size),
|
||||||
|
fFreeSpace(size),
|
||||||
fID(id),
|
fID(id),
|
||||||
fRefCount(1),
|
fRefCount(1),
|
||||||
fFaultCount(0),
|
fFaultCount(0),
|
||||||
@@ -266,14 +276,14 @@ VMAddressSpace::Get(team_id teamID)
|
|||||||
|
|
||||||
//! You must hold the address space's read lock.
|
//! You must hold the address space's read lock.
|
||||||
VMArea*
|
VMArea*
|
||||||
VMAddressSpace::LookupArea(addr_t address)
|
VMAddressSpace::LookupArea(addr_t address) const
|
||||||
{
|
{
|
||||||
// check the area hint first
|
// check the area hint first
|
||||||
VMArea* area = fAreaHint;
|
if (fAreaHint != NULL && fAreaHint->ContainsAddress(address))
|
||||||
if (area != NULL && area->ContainsAddress(address))
|
return fAreaHint;
|
||||||
return area;
|
|
||||||
|
|
||||||
for (area = areas; area != NULL; area = area->address_space_next) {
|
for (VMAddressSpaceAreaList::ConstIterator it = fAreas.GetIterator();
|
||||||
|
VMArea* area = it.Next();) {
|
||||||
if (area->id == RESERVED_AREA_ID)
|
if (area->id == RESERVED_AREA_ID)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -287,32 +297,66 @@ VMAddressSpace::LookupArea(addr_t address)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! This inserts the area you pass into the address space.
|
||||||
|
It will also set the "_address" argument to its base address when
|
||||||
|
the call succeeds.
|
||||||
|
You need to hold the VMAddressSpace write lock.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
VMAddressSpace::InsertArea(void** _address, uint32 addressSpec, addr_t size,
|
||||||
|
VMArea* area)
|
||||||
|
{
|
||||||
|
addr_t searchBase, searchEnd;
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
switch (addressSpec) {
|
||||||
|
case B_EXACT_ADDRESS:
|
||||||
|
searchBase = (addr_t)*_address;
|
||||||
|
searchEnd = (addr_t)*_address + (size - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_BASE_ADDRESS:
|
||||||
|
searchBase = (addr_t)*_address;
|
||||||
|
searchEnd = fBase + (fSize - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_ANY_ADDRESS:
|
||||||
|
case B_ANY_KERNEL_ADDRESS:
|
||||||
|
case B_ANY_KERNEL_BLOCK_ADDRESS:
|
||||||
|
searchBase = fBase;
|
||||||
|
// TODO: remove this again when vm86 mode is moved into the kernel
|
||||||
|
// completely (currently needs a userland address space!)
|
||||||
|
if (searchBase == USER_BASE)
|
||||||
|
searchBase = USER_BASE_ANY;
|
||||||
|
searchEnd = fBase + (fSize - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = _InsertAreaSlot(searchBase, size, searchEnd, addressSpec, area);
|
||||||
|
if (status == B_OK) {
|
||||||
|
*_address = (void*)area->base;
|
||||||
|
fFreeSpace -= area->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//! You must hold the address space's write lock.
|
//! You must hold the address space's write lock.
|
||||||
void
|
void
|
||||||
VMAddressSpace::RemoveArea(VMArea* area)
|
VMAddressSpace::RemoveArea(VMArea* area)
|
||||||
{
|
{
|
||||||
VMArea* temp = areas;
|
fAreas.Remove(area);
|
||||||
VMArea* last = NULL;
|
|
||||||
|
|
||||||
while (temp != NULL) {
|
if (area->id != RESERVED_AREA_ID) {
|
||||||
if (area == temp) {
|
IncrementChangeCount();
|
||||||
if (last != NULL) {
|
fFreeSpace += area->size;
|
||||||
last->address_space_next = temp->address_space_next;
|
|
||||||
} else {
|
|
||||||
areas = temp->address_space_next;
|
|
||||||
}
|
|
||||||
IncrementChangeCount();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
last = temp;
|
|
||||||
temp = temp->address_space_next;
|
|
||||||
}
|
|
||||||
if (area == fAreaHint)
|
|
||||||
fAreaHint = NULL;
|
|
||||||
|
|
||||||
if (temp == NULL) {
|
if (area == fAreaHint)
|
||||||
panic("VMAddressSpace::RemoveArea(): area not found in aspace's area "
|
fAreaHint = NULL;
|
||||||
"list\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,8 +376,8 @@ VMAddressSpace::Dump() const
|
|||||||
|
|
||||||
kprintf("area_list:\n");
|
kprintf("area_list:\n");
|
||||||
|
|
||||||
VMArea* area;
|
for (VMAddressSpaceAreaList::ConstIterator it = fAreas.GetIterator();
|
||||||
for (area = areas; area != NULL; area = area->address_space_next) {
|
VMArea* area = it.Next();) {
|
||||||
kprintf(" area 0x%lx: ", area->id);
|
kprintf(" area 0x%lx: ", area->id);
|
||||||
kprintf("base_addr = 0x%lx ", area->base);
|
kprintf("base_addr = 0x%lx ", area->base);
|
||||||
kprintf("size = 0x%lx ", area->size);
|
kprintf("size = 0x%lx ", area->size);
|
||||||
@@ -343,6 +387,313 @@ VMAddressSpace::Dump() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! 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
|
||||||
|
there are reserved regions for the remaining parts.
|
||||||
|
*/
|
||||||
|
status_t
|
||||||
|
VMAddressSpace::_InsertAreaIntoReservedRegion(addr_t start, size_t size,
|
||||||
|
VMArea* area)
|
||||||
|
{
|
||||||
|
VMArea* next;
|
||||||
|
|
||||||
|
for (VMAddressSpaceAreaList::Iterator it = fAreas.GetIterator();
|
||||||
|
(next = it.Next()) != NULL;) {
|
||||||
|
if (next->base <= start
|
||||||
|
&& next->base + (next->size - 1) >= start + (size - 1)) {
|
||||||
|
// This area covers the requested range
|
||||||
|
if (next->id != RESERVED_AREA_ID) {
|
||||||
|
// but it's not reserved space, it's a real area
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
// Now we have to transfer the requested part of the reserved
|
||||||
|
// range to the new area - and remove, resize or split the old
|
||||||
|
// reserved area.
|
||||||
|
|
||||||
|
if (start == next->base) {
|
||||||
|
// the area starts at the beginning of the reserved range
|
||||||
|
fAreas.Insert(next, area);
|
||||||
|
|
||||||
|
if (size == next->size) {
|
||||||
|
// the new area fully covers the reversed range
|
||||||
|
fAreas.Remove(next);
|
||||||
|
Put();
|
||||||
|
free(next);
|
||||||
|
} else {
|
||||||
|
// resize the reserved range behind the area
|
||||||
|
next->base += size;
|
||||||
|
next->size -= size;
|
||||||
|
}
|
||||||
|
} else if (start + size == next->base + next->size) {
|
||||||
|
// the area is at the end of the reserved range
|
||||||
|
fAreas.Insert(fAreas.GetNext(next), area);
|
||||||
|
|
||||||
|
// resize the reserved range before the area
|
||||||
|
next->size = start - next->base;
|
||||||
|
} else {
|
||||||
|
// the area splits the reserved range into two separate ones
|
||||||
|
// we need a new reserved area to cover this space
|
||||||
|
VMArea* reserved = VMArea::CreateReserved(this, next->protection);
|
||||||
|
if (reserved == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
Get();
|
||||||
|
fAreas.Insert(fAreas.GetNext(next), reserved);
|
||||||
|
fAreas.Insert(reserved, area);
|
||||||
|
|
||||||
|
// resize regions
|
||||||
|
reserved->size = next->base + next->size - start - size;
|
||||||
|
next->size = start - next->base;
|
||||||
|
reserved->base = start + size;
|
||||||
|
reserved->cache_offset = next->cache_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
area->base = start;
|
||||||
|
area->size = size;
|
||||||
|
IncrementChangeCount();
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Must be called with this address space's write lock held */
|
||||||
|
status_t
|
||||||
|
VMAddressSpace::_InsertAreaSlot(addr_t start, addr_t size, addr_t end,
|
||||||
|
uint32 addressSpec, VMArea* area)
|
||||||
|
{
|
||||||
|
VMArea* last = NULL;
|
||||||
|
VMArea* next;
|
||||||
|
bool foundSpot = false;
|
||||||
|
|
||||||
|
TRACE(("VMAddressSpace::InsertAreaSlot: address space %p, start 0x%lx, "
|
||||||
|
"size %ld, end 0x%lx, addressSpec %ld, area %p\n", this, start,
|
||||||
|
size, end, addressSpec, area));
|
||||||
|
|
||||||
|
// do some sanity checking
|
||||||
|
if (start < fBase || size == 0 || end > fBase + fSize - 1
|
||||||
|
|| start + (size - 1) > end)
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
if (addressSpec == B_EXACT_ADDRESS && area->id != RESERVED_AREA_ID) {
|
||||||
|
// search for a reserved area
|
||||||
|
status_t status = _InsertAreaIntoReservedRegion(start, size, area);
|
||||||
|
if (status == B_OK || status == B_BAD_VALUE)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
// There was no reserved area, and the slot doesn't seem to be used
|
||||||
|
// already
|
||||||
|
// TODO: this could be further optimized.
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t alignment = B_PAGE_SIZE;
|
||||||
|
if (addressSpec == B_ANY_KERNEL_BLOCK_ADDRESS) {
|
||||||
|
// align the memory to the next power of two of the size
|
||||||
|
while (alignment < size)
|
||||||
|
alignment <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = ROUNDUP(start, alignment);
|
||||||
|
|
||||||
|
// walk up to the spot where we should start searching
|
||||||
|
second_chance:
|
||||||
|
VMAddressSpaceAreaList::Iterator it = fAreas.GetIterator();
|
||||||
|
while ((next = it.Next()) != NULL) {
|
||||||
|
if (next->base > start + (size - 1)) {
|
||||||
|
// we have a winner
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the right spot depending on the address specification - the area
|
||||||
|
// will be inserted directly after "last" ("next" is not referenced anymore)
|
||||||
|
|
||||||
|
switch (addressSpec) {
|
||||||
|
case B_ANY_ADDRESS:
|
||||||
|
case B_ANY_KERNEL_ADDRESS:
|
||||||
|
case B_ANY_KERNEL_BLOCK_ADDRESS:
|
||||||
|
{
|
||||||
|
// find a hole big enough for a new area
|
||||||
|
if (last == NULL) {
|
||||||
|
// see if we can build it at the beginning of the virtual map
|
||||||
|
addr_t alignedBase = ROUNDUP(fBase, alignment);
|
||||||
|
if (is_valid_spot(fBase, alignedBase, size,
|
||||||
|
next == NULL ? end : next->base)) {
|
||||||
|
foundSpot = true;
|
||||||
|
area->base = alignedBase;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = next;
|
||||||
|
next = it.Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep walking
|
||||||
|
while (next != NULL) {
|
||||||
|
addr_t alignedBase = ROUNDUP(last->base + last->size,
|
||||||
|
alignment);
|
||||||
|
if (is_valid_spot(last->base + (last->size - 1), alignedBase,
|
||||||
|
size, next->base)) {
|
||||||
|
foundSpot = true;
|
||||||
|
area->base = alignedBase;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = next;
|
||||||
|
next = it.Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundSpot)
|
||||||
|
break;
|
||||||
|
|
||||||
|
addr_t alignedBase = ROUNDUP(last->base + last->size, alignment);
|
||||||
|
if (is_valid_spot(last->base + (last->size - 1), alignedBase,
|
||||||
|
size, end)) {
|
||||||
|
// got a spot
|
||||||
|
foundSpot = true;
|
||||||
|
area->base = alignedBase;
|
||||||
|
break;
|
||||||
|
} else if (area->id != RESERVED_AREA_ID) {
|
||||||
|
// We didn't find a free spot - if there are any reserved areas,
|
||||||
|
// we can now test those for free space
|
||||||
|
// TODO: it would make sense to start with the biggest of them
|
||||||
|
it.Rewind();
|
||||||
|
next = it.Next();
|
||||||
|
for (last = NULL; next != NULL; next = it.Next()) {
|
||||||
|
if (next->id != RESERVED_AREA_ID) {
|
||||||
|
last = next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: take free space after the reserved area into
|
||||||
|
// account!
|
||||||
|
addr_t alignedBase = ROUNDUP(next->base, alignment);
|
||||||
|
if (next->base == alignedBase && next->size == size) {
|
||||||
|
// The reserved area is entirely covered, and thus,
|
||||||
|
// removed
|
||||||
|
fAreas.Remove(next);
|
||||||
|
|
||||||
|
foundSpot = true;
|
||||||
|
area->base = alignedBase;
|
||||||
|
free(next);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((next->protection & RESERVED_AVOID_BASE) == 0
|
||||||
|
&& alignedBase == next->base && next->size >= size) {
|
||||||
|
// The new area will be placed at the beginning of the
|
||||||
|
// reserved area and the reserved area will be offset
|
||||||
|
// and resized
|
||||||
|
foundSpot = true;
|
||||||
|
next->base += size;
|
||||||
|
next->size -= size;
|
||||||
|
area->base = alignedBase;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_valid_spot(next->base, alignedBase, size,
|
||||||
|
next->base + (next->size - 1))) {
|
||||||
|
// The new area will be placed at the end of the
|
||||||
|
// reserved area, and the reserved area will be resized
|
||||||
|
// to make space
|
||||||
|
alignedBase = ROUNDDOWN(next->base + next->size - size,
|
||||||
|
alignment);
|
||||||
|
|
||||||
|
foundSpot = true;
|
||||||
|
next->size = alignedBase - next->base;
|
||||||
|
area->base = alignedBase;
|
||||||
|
last = next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_BASE_ADDRESS:
|
||||||
|
{
|
||||||
|
// find a hole big enough for a new area beginning with "start"
|
||||||
|
if (last == NULL) {
|
||||||
|
// see if we can build it at the beginning of the specified
|
||||||
|
// start
|
||||||
|
if (next == NULL || next->base > start + (size - 1)) {
|
||||||
|
foundSpot = true;
|
||||||
|
area->base = start;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = next;
|
||||||
|
next = it.Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep walking
|
||||||
|
while (next != NULL) {
|
||||||
|
if (next->base - (last->base + last->size) >= size) {
|
||||||
|
// we found a spot (it'll be filled up below)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = next;
|
||||||
|
next = it.Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_t lastEnd = last->base + (last->size - 1);
|
||||||
|
if (next != NULL || end - lastEnd >= size) {
|
||||||
|
// got a spot
|
||||||
|
foundSpot = true;
|
||||||
|
if (lastEnd < start)
|
||||||
|
area->base = start;
|
||||||
|
else
|
||||||
|
area->base = lastEnd + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we didn't find a free spot in the requested range, so we'll
|
||||||
|
// try again without any restrictions
|
||||||
|
start = fBase;
|
||||||
|
addressSpec = B_ANY_ADDRESS;
|
||||||
|
last = NULL;
|
||||||
|
goto second_chance;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_EXACT_ADDRESS:
|
||||||
|
// see if we can create it exactly here
|
||||||
|
if ((last == NULL || last->base + (last->size - 1) < start)
|
||||||
|
&& (next == NULL || next->base > start + (size - 1))) {
|
||||||
|
foundSpot = true;
|
||||||
|
area->base = start;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundSpot)
|
||||||
|
return addressSpec == B_EXACT_ADDRESS ? B_BAD_VALUE : B_NO_MEMORY;
|
||||||
|
|
||||||
|
area->size = size;
|
||||||
|
if (last)
|
||||||
|
fAreas.Insert(fAreas.GetNext(last), area);
|
||||||
|
else
|
||||||
|
fAreas.Insert(fAreas.Head(), area);
|
||||||
|
|
||||||
|
IncrementChangeCount();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*static*/ int
|
/*static*/ int
|
||||||
VMAddressSpace::_DumpCommand(int argc, char** argv)
|
VMAddressSpace::_DumpCommand(int argc, char** argv)
|
||||||
{
|
{
|
||||||
@@ -380,8 +731,8 @@ VMAddressSpace::_DumpListCommand(int argc, char** argv)
|
|||||||
while (VMAddressSpace* space = it.Next()) {
|
while (VMAddressSpace* space = it.Next()) {
|
||||||
int32 areaCount = 0;
|
int32 areaCount = 0;
|
||||||
off_t areaSize = 0;
|
off_t areaSize = 0;
|
||||||
for (VMArea* area = space->areas; area != NULL;
|
for (VMAddressSpaceAreaList::Iterator it = space->fAreas.GetIterator();
|
||||||
area = area->address_space_next) {
|
VMArea* area = it.Next();) {
|
||||||
if (area->id != RESERVED_AREA_ID
|
if (area->id != RESERVED_AREA_ID
|
||||||
&& area->cache->type != CACHE_TYPE_NULL) {
|
&& area->cache->type != CACHE_TYPE_NULL) {
|
||||||
areaCount++;
|
areaCount++;
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Copyright 2002-2009, Axel Dörfler, [email protected].
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||||
|
* Distributed under the terms of the NewOS License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <vm/VMArea.h>
|
#include <vm/VMArea.h>
|
||||||
|
|
||||||
|
#include <heap.h>
|
||||||
#include <vm/vm_priv.h>
|
#include <vm/vm_priv.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -14,6 +19,70 @@
|
|||||||
|
|
||||||
rw_lock VMAreaHash::sLock = RW_LOCK_INITIALIZER("area hash");
|
rw_lock VMAreaHash::sLock = RW_LOCK_INITIALIZER("area hash");
|
||||||
VMAreaHashTable VMAreaHash::sTable;
|
VMAreaHashTable VMAreaHash::sTable;
|
||||||
|
static area_id sNextAreaID = 1;
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - VMArea
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ VMArea*
|
||||||
|
VMArea::Create(VMAddressSpace* addressSpace, const char* name,
|
||||||
|
uint32 wiring, uint32 protection)
|
||||||
|
{
|
||||||
|
// restrict the area name to B_OS_NAME_LENGTH
|
||||||
|
size_t length = strlen(name) + 1;
|
||||||
|
if (length > B_OS_NAME_LENGTH)
|
||||||
|
length = B_OS_NAME_LENGTH;
|
||||||
|
|
||||||
|
VMArea* area = (VMArea*)malloc_nogrow(sizeof(VMArea));
|
||||||
|
if (area == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
area->name = (char*)malloc_nogrow(length);
|
||||||
|
if (area->name == NULL) {
|
||||||
|
free(area);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
strlcpy(area->name, name, length);
|
||||||
|
|
||||||
|
area->id = atomic_add(&sNextAreaID, 1);
|
||||||
|
area->base = 0;
|
||||||
|
area->size = 0;
|
||||||
|
area->protection = protection;
|
||||||
|
area->wiring = wiring;
|
||||||
|
area->memory_type = 0;
|
||||||
|
|
||||||
|
area->cache = NULL;
|
||||||
|
area->cache_offset = 0;
|
||||||
|
|
||||||
|
area->address_space = addressSpace;
|
||||||
|
area->cache_next = area->cache_prev = NULL;
|
||||||
|
area->hash_next = NULL;
|
||||||
|
new (&area->mappings) VMAreaMappings;
|
||||||
|
area->page_protections = NULL;
|
||||||
|
|
||||||
|
return area;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ VMArea*
|
||||||
|
VMArea::CreateReserved(VMAddressSpace* addressSpace, uint32 flags)
|
||||||
|
{
|
||||||
|
VMArea* reserved = (VMArea*)malloc_nogrow(sizeof(VMArea));
|
||||||
|
if (reserved == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(reserved, 0, sizeof(VMArea));
|
||||||
|
reserved->id = RESERVED_AREA_ID;
|
||||||
|
// this marks it as reserved space
|
||||||
|
reserved->protection = flags;
|
||||||
|
reserved->address_space = addressSpace;
|
||||||
|
|
||||||
|
return reserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - VMAreaHash
|
||||||
|
|
||||||
|
|
||||||
/*static*/ status_t
|
/*static*/ status_t
|
||||||
|
|||||||
+44
-526
@@ -103,7 +103,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static area_id sNextAreaID = 1;
|
|
||||||
static mutex sMappingLock = MUTEX_INITIALIZER("page mappings");
|
static mutex sMappingLock = MUTEX_INITIALIZER("page mappings");
|
||||||
static mutex sAreaCacheLock = MUTEX_INITIALIZER("area->cache");
|
static mutex sAreaCacheLock = MUTEX_INITIALIZER("area->cache");
|
||||||
|
|
||||||
@@ -136,9 +135,6 @@ static status_t map_backing_store(VMAddressSpace* addressSpace,
|
|||||||
VMArea** _area, const char* areaName, bool unmapAddressRange, bool kernel);
|
VMArea** _area, const char* areaName, bool unmapAddressRange, bool kernel);
|
||||||
|
|
||||||
|
|
||||||
static size_t sKernelAddressSpaceLeft = KERNEL_SIZE;
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -281,450 +277,6 @@ lookup_area(VMAddressSpace* addressSpace, area_id id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static VMArea*
|
|
||||||
create_reserved_area_struct(VMAddressSpace* addressSpace, uint32 flags)
|
|
||||||
{
|
|
||||||
VMArea* reserved = (VMArea*)malloc_nogrow(sizeof(VMArea));
|
|
||||||
if (reserved == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
memset(reserved, 0, sizeof(VMArea));
|
|
||||||
reserved->id = RESERVED_AREA_ID;
|
|
||||||
// this marks it as reserved space
|
|
||||||
reserved->protection = flags;
|
|
||||||
reserved->address_space = addressSpace;
|
|
||||||
|
|
||||||
return reserved;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static VMArea*
|
|
||||||
create_area_struct(VMAddressSpace* addressSpace, const char* name,
|
|
||||||
uint32 wiring, uint32 protection)
|
|
||||||
{
|
|
||||||
// restrict the area name to B_OS_NAME_LENGTH
|
|
||||||
size_t length = strlen(name) + 1;
|
|
||||||
if (length > B_OS_NAME_LENGTH)
|
|
||||||
length = B_OS_NAME_LENGTH;
|
|
||||||
|
|
||||||
VMArea* area = (VMArea*)malloc_nogrow(sizeof(VMArea));
|
|
||||||
if (area == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
area->name = (char*)malloc_nogrow(length);
|
|
||||||
if (area->name == NULL) {
|
|
||||||
free(area);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
strlcpy(area->name, name, length);
|
|
||||||
|
|
||||||
area->id = atomic_add(&sNextAreaID, 1);
|
|
||||||
area->base = 0;
|
|
||||||
area->size = 0;
|
|
||||||
area->protection = protection;
|
|
||||||
area->wiring = wiring;
|
|
||||||
area->memory_type = 0;
|
|
||||||
|
|
||||||
area->cache = NULL;
|
|
||||||
area->cache_offset = 0;
|
|
||||||
|
|
||||||
area->address_space = addressSpace;
|
|
||||||
area->address_space_next = NULL;
|
|
||||||
area->cache_next = area->cache_prev = NULL;
|
|
||||||
area->hash_next = NULL;
|
|
||||||
new (&area->mappings) VMAreaMappings;
|
|
||||||
area->page_protections = NULL;
|
|
||||||
|
|
||||||
return area;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! 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
|
|
||||||
there are reserved regions for the remaining parts.
|
|
||||||
*/
|
|
||||||
static status_t
|
|
||||||
find_reserved_area(VMAddressSpace* addressSpace, addr_t start,
|
|
||||||
addr_t size, VMArea* area)
|
|
||||||
{
|
|
||||||
VMArea* last = NULL;
|
|
||||||
VMArea* next;
|
|
||||||
|
|
||||||
next = addressSpace->areas;
|
|
||||||
while (next != NULL) {
|
|
||||||
if (next->base <= start
|
|
||||||
&& next->base + (next->size - 1) >= start + (size - 1)) {
|
|
||||||
// This area covers the requested range
|
|
||||||
if (next->id != RESERVED_AREA_ID) {
|
|
||||||
// but it's not reserved space, it's a real area
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
last = next;
|
|
||||||
next = next->address_space_next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next == NULL)
|
|
||||||
return B_ENTRY_NOT_FOUND;
|
|
||||||
|
|
||||||
// Now we have to transfer the requested part of the reserved
|
|
||||||
// range to the new area - and remove, resize or split the old
|
|
||||||
// reserved area.
|
|
||||||
|
|
||||||
if (start == next->base) {
|
|
||||||
// the area starts at the beginning of the reserved range
|
|
||||||
if (last)
|
|
||||||
last->address_space_next = area;
|
|
||||||
else
|
|
||||||
addressSpace->areas = area;
|
|
||||||
|
|
||||||
if (size == next->size) {
|
|
||||||
// the new area fully covers the reversed range
|
|
||||||
area->address_space_next = next->address_space_next;
|
|
||||||
addressSpace->Put();
|
|
||||||
free(next);
|
|
||||||
} else {
|
|
||||||
// resize the reserved range behind the area
|
|
||||||
area->address_space_next = next;
|
|
||||||
next->base += size;
|
|
||||||
next->size -= size;
|
|
||||||
}
|
|
||||||
} else if (start + size == next->base + next->size) {
|
|
||||||
// the area is at the end of the reserved range
|
|
||||||
area->address_space_next = next->address_space_next;
|
|
||||||
next->address_space_next = area;
|
|
||||||
|
|
||||||
// resize the reserved range before the area
|
|
||||||
next->size = start - next->base;
|
|
||||||
} else {
|
|
||||||
// the area splits the reserved range into two separate ones
|
|
||||||
// we need a new reserved area to cover this space
|
|
||||||
VMArea* reserved = create_reserved_area_struct(addressSpace,
|
|
||||||
next->protection);
|
|
||||||
if (reserved == NULL)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
addressSpace->Get();
|
|
||||||
reserved->address_space_next = next->address_space_next;
|
|
||||||
area->address_space_next = reserved;
|
|
||||||
next->address_space_next = area;
|
|
||||||
|
|
||||||
// resize regions
|
|
||||||
reserved->size = next->base + next->size - start - size;
|
|
||||||
next->size = start - next->base;
|
|
||||||
reserved->base = start + size;
|
|
||||||
reserved->cache_offset = next->cache_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
area->base = start;
|
|
||||||
area->size = size;
|
|
||||||
addressSpace->IncrementChangeCount();
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Verifies that an area with the given aligned base and size fits into
|
|
||||||
the spot defined by base and limit and does check for overflows.
|
|
||||||
*/
|
|
||||||
static inline bool
|
|
||||||
is_valid_spot(addr_t base, addr_t alignedBase, addr_t size, addr_t limit)
|
|
||||||
{
|
|
||||||
return (alignedBase >= base && alignedBase + (size - 1) > alignedBase
|
|
||||||
&& alignedBase + (size - 1) <= limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Must be called with this address space's write lock held */
|
|
||||||
static status_t
|
|
||||||
find_and_insert_area_slot(VMAddressSpace* addressSpace, addr_t start,
|
|
||||||
addr_t size, addr_t end, uint32 addressSpec, VMArea* area)
|
|
||||||
{
|
|
||||||
VMArea* last = NULL;
|
|
||||||
VMArea* next;
|
|
||||||
bool foundSpot = false;
|
|
||||||
|
|
||||||
TRACE(("find_and_insert_area_slot: address space %p, start 0x%lx, "
|
|
||||||
"size %ld, end 0x%lx, addressSpec %ld, area %p\n", addressSpace, start,
|
|
||||||
size, end, addressSpec, area));
|
|
||||||
|
|
||||||
// do some sanity checking
|
|
||||||
if (start < addressSpace->Base() || size == 0
|
|
||||||
|| end > addressSpace->Base() + (addressSpace->Size() - 1)
|
|
||||||
|| start + (size - 1) > end)
|
|
||||||
return B_BAD_ADDRESS;
|
|
||||||
|
|
||||||
if (addressSpec == B_EXACT_ADDRESS && area->id != RESERVED_AREA_ID) {
|
|
||||||
// search for a reserved area
|
|
||||||
status_t status = find_reserved_area(addressSpace, start, size, area);
|
|
||||||
if (status == B_OK || status == B_BAD_VALUE)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
// There was no reserved area, and the slot doesn't seem to be used
|
|
||||||
// already
|
|
||||||
// TODO: this could be further optimized.
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t alignment = B_PAGE_SIZE;
|
|
||||||
if (addressSpec == B_ANY_KERNEL_BLOCK_ADDRESS) {
|
|
||||||
// align the memory to the next power of two of the size
|
|
||||||
while (alignment < size)
|
|
||||||
alignment <<= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
start = ROUNDUP(start, alignment);
|
|
||||||
|
|
||||||
// walk up to the spot where we should start searching
|
|
||||||
second_chance:
|
|
||||||
next = addressSpace->areas;
|
|
||||||
while (next != NULL) {
|
|
||||||
if (next->base > start + (size - 1)) {
|
|
||||||
// we have a winner
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
last = next;
|
|
||||||
next = next->address_space_next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the right spot depending on the address specification - the area
|
|
||||||
// will be inserted directly after "last" ("next" is not referenced anymore)
|
|
||||||
|
|
||||||
switch (addressSpec) {
|
|
||||||
case B_ANY_ADDRESS:
|
|
||||||
case B_ANY_KERNEL_ADDRESS:
|
|
||||||
case B_ANY_KERNEL_BLOCK_ADDRESS:
|
|
||||||
{
|
|
||||||
// find a hole big enough for a new area
|
|
||||||
if (last == NULL) {
|
|
||||||
// see if we can build it at the beginning of the virtual map
|
|
||||||
addr_t alignedBase = ROUNDUP(addressSpace->Base(), alignment);
|
|
||||||
if (is_valid_spot(addressSpace->Base(), alignedBase, size,
|
|
||||||
next == NULL ? end : next->base)) {
|
|
||||||
foundSpot = true;
|
|
||||||
area->base = alignedBase;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
last = next;
|
|
||||||
next = next->address_space_next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// keep walking
|
|
||||||
while (next != NULL) {
|
|
||||||
addr_t alignedBase = ROUNDUP(last->base + last->size, alignment);
|
|
||||||
if (is_valid_spot(last->base + (last->size - 1), alignedBase,
|
|
||||||
size, next->base)) {
|
|
||||||
foundSpot = true;
|
|
||||||
area->base = alignedBase;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
last = next;
|
|
||||||
next = next->address_space_next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foundSpot)
|
|
||||||
break;
|
|
||||||
|
|
||||||
addr_t alignedBase = ROUNDUP(last->base + last->size, alignment);
|
|
||||||
if (is_valid_spot(last->base + (last->size - 1), alignedBase,
|
|
||||||
size, end)) {
|
|
||||||
// got a spot
|
|
||||||
foundSpot = true;
|
|
||||||
area->base = alignedBase;
|
|
||||||
break;
|
|
||||||
} else if (area->id != RESERVED_AREA_ID) {
|
|
||||||
// We didn't find a free spot - if there are any reserved areas,
|
|
||||||
// we can now test those for free space
|
|
||||||
// TODO: it would make sense to start with the biggest of them
|
|
||||||
next = addressSpace->areas;
|
|
||||||
for (last = NULL; next != NULL;
|
|
||||||
next = next->address_space_next) {
|
|
||||||
if (next->id != RESERVED_AREA_ID) {
|
|
||||||
last = next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: take free space after the reserved area into
|
|
||||||
// account!
|
|
||||||
addr_t alignedBase = ROUNDUP(next->base, alignment);
|
|
||||||
if (next->base == alignedBase && next->size == size) {
|
|
||||||
// The reserved area is entirely covered, and thus,
|
|
||||||
// removed
|
|
||||||
if (last)
|
|
||||||
last->address_space_next = next->address_space_next;
|
|
||||||
else
|
|
||||||
addressSpace->areas = next->address_space_next;
|
|
||||||
|
|
||||||
foundSpot = true;
|
|
||||||
area->base = alignedBase;
|
|
||||||
free(next);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((next->protection & RESERVED_AVOID_BASE) == 0
|
|
||||||
&& alignedBase == next->base && next->size >= size) {
|
|
||||||
// The new area will be placed at the beginning of the
|
|
||||||
// reserved area and the reserved area will be offset
|
|
||||||
// and resized
|
|
||||||
foundSpot = true;
|
|
||||||
next->base += size;
|
|
||||||
next->size -= size;
|
|
||||||
area->base = alignedBase;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_valid_spot(next->base, alignedBase, size,
|
|
||||||
next->base + (next->size - 1))) {
|
|
||||||
// The new area will be placed at the end of the
|
|
||||||
// reserved area, and the reserved area will be resized
|
|
||||||
// to make space
|
|
||||||
alignedBase = ROUNDDOWN(next->base + next->size - size,
|
|
||||||
alignment);
|
|
||||||
|
|
||||||
foundSpot = true;
|
|
||||||
next->size = alignedBase - next->base;
|
|
||||||
area->base = alignedBase;
|
|
||||||
last = next;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
last = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case B_BASE_ADDRESS:
|
|
||||||
{
|
|
||||||
// find a hole big enough for a new area beginning with "start"
|
|
||||||
if (last == NULL) {
|
|
||||||
// see if we can build it at the beginning of the specified start
|
|
||||||
if (next == NULL || next->base > start + (size - 1)) {
|
|
||||||
foundSpot = true;
|
|
||||||
area->base = start;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
last = next;
|
|
||||||
next = next->address_space_next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// keep walking
|
|
||||||
while (next != NULL) {
|
|
||||||
if (next->base - (last->base + last->size) >= size) {
|
|
||||||
// we found a spot (it'll be filled up below)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
last = next;
|
|
||||||
next = next->address_space_next;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr_t lastEnd = last->base + (last->size - 1);
|
|
||||||
if (next != NULL || end - lastEnd >= size) {
|
|
||||||
// got a spot
|
|
||||||
foundSpot = true;
|
|
||||||
if (lastEnd < start)
|
|
||||||
area->base = start;
|
|
||||||
else
|
|
||||||
area->base = lastEnd + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we didn't find a free spot in the requested range, so we'll
|
|
||||||
// try again without any restrictions
|
|
||||||
start = addressSpace->Base();
|
|
||||||
addressSpec = B_ANY_ADDRESS;
|
|
||||||
last = NULL;
|
|
||||||
goto second_chance;
|
|
||||||
}
|
|
||||||
|
|
||||||
case B_EXACT_ADDRESS:
|
|
||||||
// see if we can create it exactly here
|
|
||||||
if ((last == NULL || last->base + (last->size - 1) < start)
|
|
||||||
&& (next == NULL || next->base > start + (size - 1))) {
|
|
||||||
foundSpot = true;
|
|
||||||
area->base = start;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!foundSpot)
|
|
||||||
return addressSpec == B_EXACT_ADDRESS ? B_BAD_VALUE : B_NO_MEMORY;
|
|
||||||
|
|
||||||
area->size = size;
|
|
||||||
if (last) {
|
|
||||||
area->address_space_next = last->address_space_next;
|
|
||||||
last->address_space_next = area;
|
|
||||||
} else {
|
|
||||||
area->address_space_next = addressSpace->areas;
|
|
||||||
addressSpace->areas = area;
|
|
||||||
}
|
|
||||||
|
|
||||||
addressSpace->IncrementChangeCount();
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! This inserts the area you pass into the specified address space.
|
|
||||||
It will also set the "_address" argument to its base address when
|
|
||||||
the call succeeds.
|
|
||||||
You need to hold the VMAddressSpace write lock.
|
|
||||||
*/
|
|
||||||
static status_t
|
|
||||||
insert_area(VMAddressSpace* addressSpace, void** _address,
|
|
||||||
uint32 addressSpec, addr_t size, VMArea* area)
|
|
||||||
{
|
|
||||||
addr_t searchBase, searchEnd;
|
|
||||||
status_t status;
|
|
||||||
|
|
||||||
switch (addressSpec) {
|
|
||||||
case B_EXACT_ADDRESS:
|
|
||||||
searchBase = (addr_t)*_address;
|
|
||||||
searchEnd = (addr_t)*_address + (size - 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_BASE_ADDRESS:
|
|
||||||
searchBase = (addr_t)*_address;
|
|
||||||
searchEnd = addressSpace->Base() + (addressSpace->Size() - 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_ANY_ADDRESS:
|
|
||||||
case B_ANY_KERNEL_ADDRESS:
|
|
||||||
case B_ANY_KERNEL_BLOCK_ADDRESS:
|
|
||||||
searchBase = addressSpace->Base();
|
|
||||||
// TODO: remove this again when vm86 mode is moved into the kernel
|
|
||||||
// completely (currently needs a userland address space!)
|
|
||||||
if (searchBase == USER_BASE)
|
|
||||||
searchBase = USER_BASE_ANY;
|
|
||||||
searchEnd = addressSpace->Base() + (addressSpace->Size() - 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = find_and_insert_area_slot(addressSpace, searchBase, size,
|
|
||||||
searchEnd, addressSpec, area);
|
|
||||||
if (status == B_OK) {
|
|
||||||
*_address = (void*)area->base;
|
|
||||||
|
|
||||||
if (addressSpace == VMAddressSpace::Kernel())
|
|
||||||
sKernelAddressSpaceLeft -= area->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
set_area_page_protection(VMArea* area, addr_t pageAddress, uint32 protection)
|
set_area_page_protection(VMArea* area, addr_t pageAddress, uint32 protection)
|
||||||
{
|
{
|
||||||
@@ -896,12 +448,9 @@ unmap_address_range(VMAddressSpace* addressSpace, addr_t address, addr_t size,
|
|||||||
addr_t lastAddress = address + (size - 1);
|
addr_t lastAddress = address + (size - 1);
|
||||||
|
|
||||||
// Check, whether the caller is allowed to modify the concerned areas.
|
// Check, whether the caller is allowed to modify the concerned areas.
|
||||||
VMArea* area;
|
|
||||||
if (!kernel) {
|
if (!kernel) {
|
||||||
area = addressSpace->areas;
|
for (VMAddressSpace::Iterator it = addressSpace->GetIterator();
|
||||||
while (area != NULL) {
|
VMArea* area = it.Next();) {
|
||||||
VMArea* nextArea = area->address_space_next;
|
|
||||||
|
|
||||||
if (area->id != RESERVED_AREA_ID) {
|
if (area->id != RESERVED_AREA_ID) {
|
||||||
addr_t areaLast = area->base + (area->size - 1);
|
addr_t areaLast = area->base + (area->size - 1);
|
||||||
if (area->base < lastAddress && address < areaLast) {
|
if (area->base < lastAddress && address < areaLast) {
|
||||||
@@ -909,15 +458,11 @@ unmap_address_range(VMAddressSpace* addressSpace, addr_t address, addr_t size,
|
|||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
area = nextArea;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
area = addressSpace->areas;
|
for (VMAddressSpace::Iterator it = addressSpace->GetIterator();
|
||||||
while (area != NULL) {
|
VMArea* area = it.Next();) {
|
||||||
VMArea* nextArea = area->address_space_next;
|
|
||||||
|
|
||||||
if (area->id != RESERVED_AREA_ID) {
|
if (area->id != RESERVED_AREA_ID) {
|
||||||
addr_t areaLast = area->base + (area->size - 1);
|
addr_t areaLast = area->base + (area->size - 1);
|
||||||
if (area->base < lastAddress && address < areaLast) {
|
if (area->base < lastAddress && address < areaLast) {
|
||||||
@@ -929,8 +474,6 @@ unmap_address_range(VMAddressSpace* addressSpace, addr_t address, addr_t size,
|
|||||||
// can't do anything about it.
|
// can't do anything about it.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
area = nextArea;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -953,8 +496,7 @@ map_backing_store(VMAddressSpace* addressSpace, VMCache* cache,
|
|||||||
addressSpec, wiring, protection, _area, areaName));
|
addressSpec, wiring, protection, _area, areaName));
|
||||||
cache->AssertLocked();
|
cache->AssertLocked();
|
||||||
|
|
||||||
VMArea* area = create_area_struct(addressSpace, areaName, wiring,
|
VMArea* area = VMArea::Create(addressSpace, areaName, wiring, protection);
|
||||||
protection);
|
|
||||||
if (area == NULL)
|
if (area == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -1002,7 +544,7 @@ map_backing_store(VMAddressSpace* addressSpace, VMCache* cache,
|
|||||||
goto err2;
|
goto err2;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = insert_area(addressSpace, _virtualAddress, addressSpec, size, area);
|
status = addressSpace->InsertArea(_virtualAddress, addressSpec, size, area);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
// TODO: wait and try again once this is working in the backend
|
// TODO: wait and try again once this is working in the backend
|
||||||
#if 0
|
#if 0
|
||||||
@@ -1106,28 +648,18 @@ vm_unreserve_address_range(team_id team, void* address, addr_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// search area list and remove any matching reserved ranges
|
// search area list and remove any matching reserved ranges
|
||||||
|
addr_t endAddress = (addr_t)address + (size - 1);
|
||||||
VMArea* area = locker.AddressSpace()->areas;
|
for (VMAddressSpace::Iterator it = locker.AddressSpace()->GetIterator();
|
||||||
VMArea* last = NULL;
|
VMArea* area = it.Next();) {
|
||||||
while (area) {
|
|
||||||
// the area must be completely part of the reserved range
|
// the area must be completely part of the reserved range
|
||||||
if (area->id == RESERVED_AREA_ID && area->base >= (addr_t)address
|
if (area->base + (area->size - 1) > endAddress)
|
||||||
&& area->base + area->size <= (addr_t)address + size) {
|
break;
|
||||||
|
if (area->id == RESERVED_AREA_ID && area->base >= (addr_t)address) {
|
||||||
// remove reserved range
|
// remove reserved range
|
||||||
VMArea* reserved = area;
|
locker.AddressSpace()->RemoveArea(area);
|
||||||
if (last)
|
|
||||||
last->address_space_next = reserved->address_space_next;
|
|
||||||
else
|
|
||||||
locker.AddressSpace()->areas = reserved->address_space_next;
|
|
||||||
|
|
||||||
area = reserved->address_space_next;
|
|
||||||
locker.AddressSpace()->Put();
|
locker.AddressSpace()->Put();
|
||||||
free(reserved);
|
free(area);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
last = area;
|
|
||||||
area = area->address_space_next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -1152,11 +684,11 @@ vm_reserve_address_range(team_id team, void** _address, uint32 addressSpec,
|
|||||||
return B_BAD_TEAM_ID;
|
return B_BAD_TEAM_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
VMArea* area = create_reserved_area_struct(locker.AddressSpace(), flags);
|
VMArea* area = VMArea::CreateReserved(locker.AddressSpace(), flags);
|
||||||
if (area == NULL)
|
if (area == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
status_t status = insert_area(locker.AddressSpace(), _address, addressSpec,
|
status_t status = locker.AddressSpace()->InsertArea(_address, addressSpec,
|
||||||
size, area);
|
size, area);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
free(area);
|
free(area);
|
||||||
@@ -2087,9 +1619,6 @@ delete_area(VMAddressSpace* addressSpace, VMArea* area)
|
|||||||
addressSpace->RemoveArea(area);
|
addressSpace->RemoveArea(area);
|
||||||
addressSpace->Put();
|
addressSpace->Put();
|
||||||
|
|
||||||
if (addressSpace == VMAddressSpace::Kernel())
|
|
||||||
sKernelAddressSpaceLeft -= area->size;
|
|
||||||
|
|
||||||
area->cache->RemoveArea(area);
|
area->cache->RemoveArea(area);
|
||||||
area->cache->ReleaseRef();
|
area->cache->ReleaseRef();
|
||||||
|
|
||||||
@@ -3360,10 +2889,6 @@ dump_available_memory(int argc, char** argv)
|
|||||||
status_t
|
status_t
|
||||||
vm_delete_areas(struct VMAddressSpace* addressSpace)
|
vm_delete_areas(struct VMAddressSpace* addressSpace)
|
||||||
{
|
{
|
||||||
VMArea* area;
|
|
||||||
VMArea* next;
|
|
||||||
VMArea* last = NULL;
|
|
||||||
|
|
||||||
TRACE(("vm_delete_areas: called on address space 0x%lx\n",
|
TRACE(("vm_delete_areas: called on address space 0x%lx\n",
|
||||||
addressSpace->ID()));
|
addressSpace->ID()));
|
||||||
|
|
||||||
@@ -3371,30 +2896,19 @@ vm_delete_areas(struct VMAddressSpace* addressSpace)
|
|||||||
|
|
||||||
// remove all reserved areas in this address space
|
// remove all reserved areas in this address space
|
||||||
|
|
||||||
for (area = addressSpace->areas; area; area = next) {
|
for (VMAddressSpace::Iterator it = addressSpace->GetIterator();
|
||||||
next = area->address_space_next;
|
VMArea* area = it.Next();) {
|
||||||
|
|
||||||
if (area->id == RESERVED_AREA_ID) {
|
if (area->id == RESERVED_AREA_ID) {
|
||||||
// just remove it
|
// just remove it
|
||||||
if (last)
|
addressSpace->RemoveArea(area);
|
||||||
last->address_space_next = area->address_space_next;
|
|
||||||
else
|
|
||||||
addressSpace->areas = area->address_space_next;
|
|
||||||
|
|
||||||
addressSpace->Put();
|
addressSpace->Put();
|
||||||
free(area);
|
free(area);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
last = area;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete all the areas in this address space
|
// delete all the areas in this address space
|
||||||
|
while (VMArea* area = addressSpace->FirstArea())
|
||||||
for (area = addressSpace->areas; area; area = next) {
|
|
||||||
next = area->address_space_next;
|
|
||||||
delete_area(addressSpace, area);
|
delete_area(addressSpace, area);
|
||||||
}
|
|
||||||
|
|
||||||
addressSpace->WriteUnlock();
|
addressSpace->WriteUnlock();
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -3430,6 +2944,7 @@ vm_area_for(addr_t address, bool kernel)
|
|||||||
|
|
||||||
|
|
||||||
/*! Frees physical pages that were used during the boot process.
|
/*! Frees physical pages that were used during the boot process.
|
||||||
|
\a end is inclusive.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
unmap_and_free_physical_pages(vm_translation_map* map, addr_t start, addr_t end)
|
unmap_and_free_physical_pages(vm_translation_map* map, addr_t start, addr_t end)
|
||||||
@@ -3448,7 +2963,7 @@ unmap_and_free_physical_pages(vm_translation_map* map, addr_t start, addr_t end)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// unmap the memory
|
// unmap the memory
|
||||||
map->ops->unmap(map, start, end - 1);
|
map->ops->unmap(map, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3456,9 +2971,8 @@ void
|
|||||||
vm_free_unused_boot_loader_range(addr_t start, addr_t size)
|
vm_free_unused_boot_loader_range(addr_t start, addr_t size)
|
||||||
{
|
{
|
||||||
vm_translation_map* map = &VMAddressSpace::Kernel()->TranslationMap();
|
vm_translation_map* map = &VMAddressSpace::Kernel()->TranslationMap();
|
||||||
addr_t end = start + size;
|
addr_t end = start + (size - 1);
|
||||||
addr_t lastEnd = start;
|
addr_t lastEnd = start;
|
||||||
VMArea* area;
|
|
||||||
|
|
||||||
TRACE(("vm_free_unused_boot_loader_range(): asked to free %p - %p\n",
|
TRACE(("vm_free_unused_boot_loader_range(): asked to free %p - %p\n",
|
||||||
(void*)start, (void*)end));
|
(void*)start, (void*)end));
|
||||||
@@ -3469,17 +2983,17 @@ vm_free_unused_boot_loader_range(addr_t start, addr_t size)
|
|||||||
|
|
||||||
map->ops->lock(map);
|
map->ops->lock(map);
|
||||||
|
|
||||||
for (area = VMAddressSpace::Kernel()->areas; area != NULL;
|
for (VMAddressSpace::Iterator it = VMAddressSpace::Kernel()->GetIterator();
|
||||||
area = area->address_space_next) {
|
VMArea* area = it.Next();) {
|
||||||
addr_t areaStart = area->base;
|
addr_t areaStart = area->base;
|
||||||
addr_t areaEnd = areaStart + area->size;
|
addr_t areaEnd = areaStart + (area->size - 1);
|
||||||
|
|
||||||
if (area->id == RESERVED_AREA_ID)
|
if (area->id == RESERVED_AREA_ID || areaEnd < start)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (areaEnd >= end) {
|
if (areaStart > end) {
|
||||||
// we are done, the areas are already beyond of what we have to free
|
// we are done, the area is already beyond of what we have to free
|
||||||
lastEnd = end;
|
end = areaStart - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3487,10 +3001,16 @@ vm_free_unused_boot_loader_range(addr_t start, addr_t size)
|
|||||||
// this is something we can free
|
// this is something we can free
|
||||||
TRACE(("free boot range: get rid of %p - %p\n", (void*)lastEnd,
|
TRACE(("free boot range: get rid of %p - %p\n", (void*)lastEnd,
|
||||||
(void*)areaStart));
|
(void*)areaStart));
|
||||||
unmap_and_free_physical_pages(map, lastEnd, areaStart);
|
unmap_and_free_physical_pages(map, lastEnd, areaStart - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastEnd = areaEnd;
|
if (areaEnd >= end) {
|
||||||
|
lastEnd = areaEnd;
|
||||||
|
// no +1 to prevent potential overflow
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastEnd = areaEnd + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastEnd < end) {
|
if (lastEnd < end) {
|
||||||
@@ -3747,8 +3267,6 @@ vm_init(kernel_args* args)
|
|||||||
err = arch_vm_init(args);
|
err = arch_vm_init(args);
|
||||||
|
|
||||||
// initialize some globals
|
// initialize some globals
|
||||||
sNextAreaID = 1;
|
|
||||||
|
|
||||||
vm_page_init_num_pages(args);
|
vm_page_init_num_pages(args);
|
||||||
sAvailableMemory = vm_page_num_pages() * B_PAGE_SIZE;
|
sAvailableMemory = vm_page_num_pages() * B_PAGE_SIZE;
|
||||||
|
|
||||||
@@ -4545,7 +4063,7 @@ vm_available_not_needed_memory(void)
|
|||||||
size_t
|
size_t
|
||||||
vm_kernel_address_space_left(void)
|
vm_kernel_address_space_left(void)
|
||||||
{
|
{
|
||||||
return sKernelAddressSpaceLeft;
|
return VMAddressSpace::Kernel()->FreeSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4724,7 +4242,7 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
|
|||||||
|
|
||||||
for (VMArea* current = cache->areas; current != NULL;
|
for (VMArea* current = cache->areas; current != NULL;
|
||||||
current = current->cache_next) {
|
current = current->cache_next) {
|
||||||
VMArea* next = current->address_space_next;
|
VMArea* next = current->address_space->NextArea(current);
|
||||||
if (next != NULL && next->base <= (current->base + newSize)) {
|
if (next != NULL && next->base <= (current->base + newSize)) {
|
||||||
// If the area was created inside a reserved area, it can
|
// If the area was created inside a reserved area, it can
|
||||||
// also be resized in that area
|
// also be resized in that area
|
||||||
@@ -4752,7 +4270,7 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
|
|||||||
|
|
||||||
for (VMArea* current = cache->areas; current != NULL;
|
for (VMArea* current = cache->areas; current != NULL;
|
||||||
current = current->cache_next) {
|
current = current->cache_next) {
|
||||||
VMArea* next = current->address_space_next;
|
VMArea* next = current->address_space->NextArea(current);
|
||||||
if (next != NULL && next->base <= (current->base + newSize)) {
|
if (next != NULL && next->base <= (current->base + newSize)) {
|
||||||
if (next->id == RESERVED_AREA_ID
|
if (next->id == RESERVED_AREA_ID
|
||||||
&& next->cache_offset <= current->base
|
&& next->cache_offset <= current->base
|
||||||
@@ -4760,7 +4278,7 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
|
|||||||
// resize reserved area
|
// resize reserved area
|
||||||
addr_t offset = current->base + newSize - next->base;
|
addr_t offset = current->base + newSize - next->base;
|
||||||
if (next->size <= offset) {
|
if (next->size <= offset) {
|
||||||
current->address_space_next = next->address_space_next;
|
next->address_space->RemoveArea(next);
|
||||||
free(next);
|
free(next);
|
||||||
} else {
|
} else {
|
||||||
next->size -= offset;
|
next->size -= offset;
|
||||||
@@ -5254,8 +4772,8 @@ _get_next_area_info(team_id team, int32* cookie, area_info* info, size_t size)
|
|||||||
return B_BAD_TEAM_ID;
|
return B_BAD_TEAM_ID;
|
||||||
|
|
||||||
VMArea* area;
|
VMArea* area;
|
||||||
for (area = locker.AddressSpace()->areas; area != NULL;
|
for (VMAddressSpace::Iterator it = locker.AddressSpace()->GetIterator();
|
||||||
area = area->address_space_next) {
|
(area = it.Next()) != NULL;) {
|
||||||
if (area->id == RESERVED_AREA_ID)
|
if (area->id == RESERVED_AREA_ID)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user