2 * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
4 * Distributed under the terms of the MIT License.
6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
7 * Distributed under the terms of the NewOS License.
11 #include <vm/VMAddressSpace.h>
17 #include <KernelExport.h>
19 #include <util/OpenHashTable.h>
24 #include <vm/VMArea.h>
25 #include <vm/VMCache.h>
27 #include "VMKernelAddressSpace.h"
28 #include "VMUserAddressSpace.h"
33 # define TRACE(x) dprintf x
39 #define ASPACE_HASH_TABLE_SIZE 1024
42 // #pragma mark - AddressSpaceHashDefinition
47 struct AddressSpaceHashDefinition
{
48 typedef team_id KeyType
;
49 typedef VMAddressSpace ValueType
;
51 size_t HashKey(team_id key
) const
56 size_t Hash(const VMAddressSpace
* value
) const
58 return HashKey(value
->ID());
61 bool Compare(team_id key
, const VMAddressSpace
* value
) const
63 return value
->ID() == key
;
66 VMAddressSpace
*& GetLink(VMAddressSpace
* value
) const
68 return value
->HashTableLink();
72 typedef BOpenHashTable
<AddressSpaceHashDefinition
> AddressSpaceTable
;
77 static AddressSpaceTable sAddressSpaceTable
;
78 static rw_lock sAddressSpaceTableLock
;
80 VMAddressSpace
* VMAddressSpace::sKernelAddressSpace
;
83 // #pragma mark - VMAddressSpace
86 VMAddressSpace::VMAddressSpace(team_id id
, addr_t base
, size_t size
,
90 fEndAddress(base
+ (size
- 1)),
96 fTranslationMap(NULL
),
97 fRandomizingEnabled(true),
100 rw_lock_init(&fLock
, name
);
101 // rw_lock_init(&fLock, kernel ? "kernel address space" : "address space");
105 VMAddressSpace::~VMAddressSpace()
107 TRACE(("VMAddressSpace::~VMAddressSpace: called on aspace %" B_PRId32
"\n",
112 delete fTranslationMap
;
114 rw_lock_destroy(&fLock
);
119 VMAddressSpace::Init()
121 rw_lock_init(&sAddressSpaceTableLock
, "address spaces table");
123 // create the area and address space hash tables
125 new(&sAddressSpaceTable
) AddressSpaceTable
;
126 status_t error
= sAddressSpaceTable
.Init(ASPACE_HASH_TABLE_SIZE
);
128 panic("vm_init: error creating aspace hash table\n");
131 // create the initial kernel address space
132 if (Create(B_SYSTEM_TEAM
, KERNEL_BASE
, KERNEL_SIZE
, true,
133 &sKernelAddressSpace
) != B_OK
) {
134 panic("vm_init: error creating kernel address space!\n");
137 add_debugger_command("aspaces", &_DumpListCommand
,
138 "Dump a list of all address spaces");
139 add_debugger_command("aspace", &_DumpCommand
,
140 "Dump info about a particular address space");
146 /*! Deletes all areas in the specified address space, and the address
147 space by decreasing all reference counters. It also marks the
148 address space of being in deletion state, so that no more areas
149 can be created in it.
150 After this, the address space is not operational anymore, but might
151 still be in memory until the last reference has been released.
154 VMAddressSpace::RemoveAndPut()
160 vm_delete_areas(this, true);
166 VMAddressSpace::InitObject()
173 VMAddressSpace::Dump() const
175 kprintf("dump of address space at %p:\n", this);
176 kprintf("id: %" B_PRId32
"\n", fID
);
177 kprintf("ref_count: %" B_PRId32
"\n", fRefCount
);
178 kprintf("fault_count: %" B_PRId32
"\n", fFaultCount
);
179 kprintf("translation_map: %p\n", fTranslationMap
);
180 kprintf("base: %#" B_PRIxADDR
"\n", fBase
);
181 kprintf("end: %#" B_PRIxADDR
"\n", fEndAddress
);
182 kprintf("change_count: %" B_PRId32
"\n", fChangeCount
);
187 VMAddressSpace::Create(team_id teamID
, addr_t base
, size_t size
, bool kernel
,
188 VMAddressSpace
** _addressSpace
)
190 VMAddressSpace
* addressSpace
= kernel
191 ? (VMAddressSpace
*)new(std::nothrow
) VMKernelAddressSpace(teamID
, base
,
193 : (VMAddressSpace
*)new(std::nothrow
) VMUserAddressSpace(teamID
, base
,
195 if (addressSpace
== NULL
)
198 status_t status
= addressSpace
->InitObject();
199 if (status
!= B_OK
) {
204 TRACE(("VMAddressSpace::Create(): team %" B_PRId32
" (%skernel): %#lx "
205 "bytes starting at %#lx => %p\n", teamID
, kernel
? "" : "!", size
,
206 base
, addressSpace
));
208 // create the corresponding translation map
209 status
= arch_vm_translation_map_create_map(kernel
,
210 &addressSpace
->fTranslationMap
);
211 if (status
!= B_OK
) {
216 // add the aspace to the global hash table
217 rw_lock_write_lock(&sAddressSpaceTableLock
);
218 sAddressSpaceTable
.InsertUnchecked(addressSpace
);
219 rw_lock_write_unlock(&sAddressSpaceTableLock
);
221 *_addressSpace
= addressSpace
;
226 /*static*/ VMAddressSpace
*
227 VMAddressSpace::GetKernel()
229 // we can treat this one a little differently since it can't be deleted
230 sKernelAddressSpace
->Get();
231 return sKernelAddressSpace
;
236 VMAddressSpace::CurrentID()
238 Thread
* thread
= thread_get_current_thread();
240 if (thread
!= NULL
&& thread
->team
->address_space
!= NULL
)
241 return thread
->team
->id
;
247 /*static*/ VMAddressSpace
*
248 VMAddressSpace::GetCurrent()
250 Thread
* thread
= thread_get_current_thread();
252 if (thread
!= NULL
) {
253 VMAddressSpace
* addressSpace
= thread
->team
->address_space
;
254 if (addressSpace
!= NULL
) {
264 /*static*/ VMAddressSpace
*
265 VMAddressSpace::Get(team_id teamID
)
267 rw_lock_read_lock(&sAddressSpaceTableLock
);
268 VMAddressSpace
* addressSpace
= sAddressSpaceTable
.Lookup(teamID
);
271 rw_lock_read_unlock(&sAddressSpaceTableLock
);
277 /*static*/ VMAddressSpace
*
278 VMAddressSpace::DebugFirst()
280 return sAddressSpaceTable
.GetIterator().Next();
284 /*static*/ VMAddressSpace
*
285 VMAddressSpace::DebugNext(VMAddressSpace
* addressSpace
)
287 if (addressSpace
== NULL
)
290 AddressSpaceTable::Iterator it
291 = sAddressSpaceTable
.GetIterator(addressSpace
->ID());
297 /*static*/ VMAddressSpace
*
298 VMAddressSpace::DebugGet(team_id teamID
)
300 return sAddressSpaceTable
.Lookup(teamID
);
305 VMAddressSpace::_DeleteIfUnreferenced(team_id id
)
307 rw_lock_write_lock(&sAddressSpaceTableLock
);
310 VMAddressSpace
* addressSpace
= sAddressSpaceTable
.Lookup(id
);
311 if (addressSpace
!= NULL
&& addressSpace
->fRefCount
== 0) {
312 sAddressSpaceTable
.RemoveUnchecked(addressSpace
);
316 rw_lock_write_unlock(&sAddressSpaceTableLock
);
324 VMAddressSpace::_DumpCommand(int argc
, char** argv
)
326 VMAddressSpace
* aspace
;
329 kprintf("aspace: not enough arguments\n");
333 // if the argument looks like a number, treat it as such
336 team_id id
= strtoul(argv
[1], NULL
, 0);
338 aspace
= sAddressSpaceTable
.Lookup(id
);
339 if (aspace
== NULL
) {
340 kprintf("invalid aspace id\n");
351 VMAddressSpace::_DumpListCommand(int argc
, char** argv
)
353 kprintf(" %*s id %*s %*s area count area size\n",
354 B_PRINTF_POINTER_WIDTH
, "address", B_PRINTF_POINTER_WIDTH
, "base",
355 B_PRINTF_POINTER_WIDTH
, "end");
357 AddressSpaceTable::Iterator it
= sAddressSpaceTable
.GetIterator();
358 while (VMAddressSpace
* space
= it
.Next()) {
361 for (VMAddressSpace::AreaIterator areaIt
= space
->GetAreaIterator();
362 VMArea
* area
= areaIt
.Next();) {
364 areaSize
+= area
->Size();
366 kprintf("%p %6" B_PRId32
" %#010" B_PRIxADDR
" %#10" B_PRIxADDR
367 " %10" B_PRId32
" %10" B_PRIdOFF
"\n", space
, space
->ID(),
368 space
->Base(), space
->EndAddress(), areaCount
, areaSize
);