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