1 /* 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. 5 * 6 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the NewOS License. 8 */ 9 10 11 #include <vm/VMAddressSpace.h> 12 13 #include <stdlib.h> 14 15 #include <new> 16 17 #include <KernelExport.h> 18 19 #include <util/OpenHashTable.h> 20 21 #include <heap.h> 22 #include <thread.h> 23 #include <vm/vm.h> 24 #include <vm/VMArea.h> 25 #include <vm/VMCache.h> 26 27 #include "VMKernelAddressSpace.h" 28 #include "VMUserAddressSpace.h" 29 30 31 //#define TRACE_VM 32 #ifdef TRACE_VM 33 # define TRACE(x) dprintf x 34 #else 35 # define TRACE(x) ; 36 #endif 37 38 39 #define ASPACE_HASH_TABLE_SIZE 1024 40 41 42 // #pragma mark - AddressSpaceHashDefinition 43 44 45 namespace { 46 47 struct AddressSpaceHashDefinition { 48 typedef team_id KeyType; 49 typedef VMAddressSpace ValueType; 50 51 size_t HashKey(team_id key) const 52 { 53 return key; 54 } 55 56 size_t Hash(const VMAddressSpace* value) const 57 { 58 return HashKey(value->ID()); 59 } 60 61 bool Compare(team_id key, const VMAddressSpace* value) const 62 { 63 return value->ID() == key; 64 } 65 66 VMAddressSpace*& GetLink(VMAddressSpace* value) const 67 { 68 return value->HashTableLink(); 69 } 70 }; 71 72 typedef BOpenHashTable<AddressSpaceHashDefinition> AddressSpaceTable; 73 74 } // namespace 75 76 77 static AddressSpaceTable sAddressSpaceTable; 78 static rw_lock sAddressSpaceTableLock; 79 80 VMAddressSpace* VMAddressSpace::sKernelAddressSpace; 81 82 83 // #pragma mark - VMAddressSpace 84 85 86 VMAddressSpace::VMAddressSpace(team_id id, addr_t base, size_t size, 87 const char* name) 88 : 89 fBase(base), 90 fEndAddress(base + (size - 1)), 91 fFreeSpace(size), 92 fID(id), 93 fRefCount(1), 94 fFaultCount(0), 95 fChangeCount(0), 96 fTranslationMap(NULL), 97 fRandomizingEnabled(true), 98 fDeleting(false) 99 { 100 rw_lock_init(&fLock, name); 101 } 102 103 104 VMAddressSpace::~VMAddressSpace() 105 { 106 TRACE(("VMAddressSpace::~VMAddressSpace: called on aspace %" B_PRId32 "\n", 107 ID())); 108 109 WriteLock(); 110 111 delete fTranslationMap; 112 113 rw_lock_destroy(&fLock); 114 } 115 116 117 /*static*/ status_t 118 VMAddressSpace::Init() 119 { 120 rw_lock_init(&sAddressSpaceTableLock, "address spaces table"); 121 122 // create the area and address space hash tables 123 { 124 new(&sAddressSpaceTable) AddressSpaceTable; 125 status_t error = sAddressSpaceTable.Init(ASPACE_HASH_TABLE_SIZE); 126 if (error != B_OK) 127 panic("vm_init: error creating aspace hash table\n"); 128 } 129 130 // create the initial kernel address space 131 if (Create(B_SYSTEM_TEAM, KERNEL_BASE, KERNEL_SIZE, true, 132 &sKernelAddressSpace) != B_OK) { 133 panic("vm_init: error creating kernel address space!\n"); 134 } 135 136 add_debugger_command("aspaces", &_DumpListCommand, 137 "Dump a list of all address spaces"); 138 add_debugger_command("aspace", &_DumpCommand, 139 "Dump info about a particular address space"); 140 141 return B_OK; 142 } 143 144 145 /*! Deletes all areas in the specified address space, and the address 146 space by decreasing all reference counters. It also marks the 147 address space of being in deletion state, so that no more areas 148 can be created in it. 149 After this, the address space is not operational anymore, but might 150 still be in memory until the last reference has been released. 151 */ 152 void 153 VMAddressSpace::RemoveAndPut() 154 { 155 WriteLock(); 156 fDeleting = true; 157 WriteUnlock(); 158 159 vm_delete_areas(this, true); 160 Put(); 161 } 162 163 164 status_t 165 VMAddressSpace::InitObject() 166 { 167 return B_OK; 168 } 169 170 171 void 172 VMAddressSpace::Dump() const 173 { 174 kprintf("dump of address space at %p:\n", this); 175 kprintf("id: %" B_PRId32 "\n", fID); 176 kprintf("ref_count: %" B_PRId32 "\n", fRefCount); 177 kprintf("fault_count: %" B_PRId32 "\n", fFaultCount); 178 kprintf("translation_map: %p\n", fTranslationMap); 179 kprintf("base: %#" B_PRIxADDR "\n", fBase); 180 kprintf("end: %#" B_PRIxADDR "\n", fEndAddress); 181 kprintf("change_count: %" B_PRId32 "\n", fChangeCount); 182 } 183 184 185 /*static*/ status_t 186 VMAddressSpace::Create(team_id teamID, addr_t base, size_t size, bool kernel, 187 VMAddressSpace** _addressSpace) 188 { 189 VMAddressSpace* addressSpace = kernel 190 ? (VMAddressSpace*)new(std::nothrow) VMKernelAddressSpace(teamID, base, 191 size) 192 : (VMAddressSpace*)new(std::nothrow) VMUserAddressSpace(teamID, base, 193 size); 194 if (addressSpace == NULL) 195 return B_NO_MEMORY; 196 197 status_t status = addressSpace->InitObject(); 198 if (status != B_OK) { 199 delete addressSpace; 200 return status; 201 } 202 203 TRACE(("VMAddressSpace::Create(): team %" B_PRId32 " (%skernel): %#lx " 204 "bytes starting at %#lx => %p\n", teamID, kernel ? "" : "!", size, 205 base, addressSpace)); 206 207 // create the corresponding translation map 208 status = arch_vm_translation_map_create_map(kernel, 209 &addressSpace->fTranslationMap); 210 if (status != B_OK) { 211 delete addressSpace; 212 return status; 213 } 214 215 // add the aspace to the global hash table 216 rw_lock_write_lock(&sAddressSpaceTableLock); 217 sAddressSpaceTable.InsertUnchecked(addressSpace); 218 rw_lock_write_unlock(&sAddressSpaceTableLock); 219 220 *_addressSpace = addressSpace; 221 return B_OK; 222 } 223 224 225 /*static*/ VMAddressSpace* 226 VMAddressSpace::GetKernel() 227 { 228 // we can treat this one a little differently since it can't be deleted 229 sKernelAddressSpace->Get(); 230 return sKernelAddressSpace; 231 } 232 233 234 /*static*/ team_id 235 VMAddressSpace::CurrentID() 236 { 237 Thread* thread = thread_get_current_thread(); 238 239 if (thread != NULL && thread->team->address_space != NULL) 240 return thread->team->id; 241 242 return B_ERROR; 243 } 244 245 246 /*static*/ VMAddressSpace* 247 VMAddressSpace::GetCurrent() 248 { 249 Thread* thread = thread_get_current_thread(); 250 251 if (thread != NULL) { 252 VMAddressSpace* addressSpace = thread->team->address_space; 253 if (addressSpace != NULL) { 254 addressSpace->Get(); 255 return addressSpace; 256 } 257 } 258 259 return NULL; 260 } 261 262 263 /*static*/ VMAddressSpace* 264 VMAddressSpace::Get(team_id teamID) 265 { 266 rw_lock_read_lock(&sAddressSpaceTableLock); 267 VMAddressSpace* addressSpace = sAddressSpaceTable.Lookup(teamID); 268 if (addressSpace) 269 addressSpace->Get(); 270 rw_lock_read_unlock(&sAddressSpaceTableLock); 271 272 return addressSpace; 273 } 274 275 276 /*static*/ VMAddressSpace* 277 VMAddressSpace::DebugFirst() 278 { 279 return sAddressSpaceTable.GetIterator().Next(); 280 } 281 282 283 /*static*/ VMAddressSpace* 284 VMAddressSpace::DebugNext(VMAddressSpace* addressSpace) 285 { 286 if (addressSpace == NULL) 287 return NULL; 288 289 AddressSpaceTable::Iterator it 290 = sAddressSpaceTable.GetIterator(addressSpace->ID()); 291 it.Next(); 292 return it.Next(); 293 } 294 295 296 /*static*/ VMAddressSpace* 297 VMAddressSpace::DebugGet(team_id teamID) 298 { 299 return sAddressSpaceTable.Lookup(teamID); 300 } 301 302 303 /*static*/ void 304 VMAddressSpace::_DeleteIfUnreferenced(team_id id) 305 { 306 rw_lock_write_lock(&sAddressSpaceTableLock); 307 308 bool remove = false; 309 VMAddressSpace* addressSpace = sAddressSpaceTable.Lookup(id); 310 if (addressSpace != NULL && addressSpace->fRefCount == 0) { 311 sAddressSpaceTable.RemoveUnchecked(addressSpace); 312 remove = true; 313 } 314 315 rw_lock_write_unlock(&sAddressSpaceTableLock); 316 317 if (remove) 318 delete addressSpace; 319 } 320 321 322 /*static*/ int 323 VMAddressSpace::_DumpCommand(int argc, char** argv) 324 { 325 VMAddressSpace* aspace; 326 327 if (argc < 2) { 328 kprintf("aspace: not enough arguments\n"); 329 return 0; 330 } 331 332 // if the argument looks like a number, treat it as such 333 334 { 335 team_id id = strtoul(argv[1], NULL, 0); 336 337 aspace = sAddressSpaceTable.Lookup(id); 338 if (aspace == NULL) { 339 kprintf("invalid aspace id\n"); 340 } else { 341 aspace->Dump(); 342 } 343 } 344 345 return 0; 346 } 347 348 349 /*static*/ int 350 VMAddressSpace::_DumpListCommand(int argc, char** argv) 351 { 352 kprintf(" %*s id %*s %*s area count area size\n", 353 B_PRINTF_POINTER_WIDTH, "address", B_PRINTF_POINTER_WIDTH, "base", 354 B_PRINTF_POINTER_WIDTH, "end"); 355 356 AddressSpaceTable::Iterator it = sAddressSpaceTable.GetIterator(); 357 while (VMAddressSpace* space = it.Next()) { 358 int32 areaCount = 0; 359 off_t areaSize = 0; 360 for (VMAddressSpace::AreaIterator areaIt = space->GetAreaIterator(); 361 VMArea* area = areaIt.Next();) { 362 areaCount++; 363 areaSize += area->Size(); 364 } 365 kprintf("%p %6" B_PRId32 " %#010" B_PRIxADDR " %#10" B_PRIxADDR 366 " %10" B_PRId32 " %10" B_PRIdOFF "\n", space, space->ID(), 367 space->Base(), space->EndAddress(), areaCount, areaSize); 368 } 369 370 return 0; 371 } 372