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 // rw_lock_init(&fLock, kernel ? "kernel address space" : "address space"); 102 } 103 104 105 VMAddressSpace::~VMAddressSpace() 106 { 107 TRACE(("VMAddressSpace::~VMAddressSpace: called on aspace %" B_PRId32 "\n", 108 ID())); 109 110 WriteLock(); 111 112 delete fTranslationMap; 113 114 rw_lock_destroy(&fLock); 115 } 116 117 118 /*static*/ status_t 119 VMAddressSpace::Init() 120 { 121 rw_lock_init(&sAddressSpaceTableLock, "address spaces table"); 122 123 // create the area and address space hash tables 124 { 125 new(&sAddressSpaceTable) AddressSpaceTable; 126 status_t error = sAddressSpaceTable.Init(ASPACE_HASH_TABLE_SIZE); 127 if (error != B_OK) 128 panic("vm_init: error creating aspace hash table\n"); 129 } 130 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"); 135 } 136 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"); 141 142 return B_OK; 143 } 144 145 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. 152 */ 153 void 154 VMAddressSpace::RemoveAndPut() 155 { 156 WriteLock(); 157 fDeleting = true; 158 WriteUnlock(); 159 160 vm_delete_areas(this, true); 161 Put(); 162 } 163 164 165 status_t 166 VMAddressSpace::InitObject() 167 { 168 return B_OK; 169 } 170 171 172 void 173 VMAddressSpace::Dump() const 174 { 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); 183 } 184 185 186 /*static*/ status_t 187 VMAddressSpace::Create(team_id teamID, addr_t base, size_t size, bool kernel, 188 VMAddressSpace** _addressSpace) 189 { 190 VMAddressSpace* addressSpace = kernel 191 ? (VMAddressSpace*)new(std::nothrow) VMKernelAddressSpace(teamID, base, 192 size) 193 : (VMAddressSpace*)new(std::nothrow) VMUserAddressSpace(teamID, base, 194 size); 195 if (addressSpace == NULL) 196 return B_NO_MEMORY; 197 198 status_t status = addressSpace->InitObject(); 199 if (status != B_OK) { 200 delete addressSpace; 201 return status; 202 } 203 204 TRACE(("VMAddressSpace::Create(): team %" B_PRId32 " (%skernel): %#lx " 205 "bytes starting at %#lx => %p\n", teamID, kernel ? "" : "!", size, 206 base, addressSpace)); 207 208 // create the corresponding translation map 209 status = arch_vm_translation_map_create_map(kernel, 210 &addressSpace->fTranslationMap); 211 if (status != B_OK) { 212 delete addressSpace; 213 return status; 214 } 215 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); 220 221 *_addressSpace = addressSpace; 222 return B_OK; 223 } 224 225 226 /*static*/ VMAddressSpace* 227 VMAddressSpace::GetKernel() 228 { 229 // we can treat this one a little differently since it can't be deleted 230 sKernelAddressSpace->Get(); 231 return sKernelAddressSpace; 232 } 233 234 235 /*static*/ team_id 236 VMAddressSpace::CurrentID() 237 { 238 Thread* thread = thread_get_current_thread(); 239 240 if (thread != NULL && thread->team->address_space != NULL) 241 return thread->team->id; 242 243 return B_ERROR; 244 } 245 246 247 /*static*/ VMAddressSpace* 248 VMAddressSpace::GetCurrent() 249 { 250 Thread* thread = thread_get_current_thread(); 251 252 if (thread != NULL) { 253 VMAddressSpace* addressSpace = thread->team->address_space; 254 if (addressSpace != NULL) { 255 addressSpace->Get(); 256 return addressSpace; 257 } 258 } 259 260 return NULL; 261 } 262 263 264 /*static*/ VMAddressSpace* 265 VMAddressSpace::Get(team_id teamID) 266 { 267 rw_lock_read_lock(&sAddressSpaceTableLock); 268 VMAddressSpace* addressSpace = sAddressSpaceTable.Lookup(teamID); 269 if (addressSpace) 270 addressSpace->Get(); 271 rw_lock_read_unlock(&sAddressSpaceTableLock); 272 273 return addressSpace; 274 } 275 276 277 /*static*/ VMAddressSpace* 278 VMAddressSpace::DebugFirst() 279 { 280 return sAddressSpaceTable.GetIterator().Next(); 281 } 282 283 284 /*static*/ VMAddressSpace* 285 VMAddressSpace::DebugNext(VMAddressSpace* addressSpace) 286 { 287 if (addressSpace == NULL) 288 return NULL; 289 290 AddressSpaceTable::Iterator it 291 = sAddressSpaceTable.GetIterator(addressSpace->ID()); 292 it.Next(); 293 return it.Next(); 294 } 295 296 297 /*static*/ VMAddressSpace* 298 VMAddressSpace::DebugGet(team_id teamID) 299 { 300 return sAddressSpaceTable.Lookup(teamID); 301 } 302 303 304 /*static*/ void 305 VMAddressSpace::_DeleteIfUnreferenced(team_id id) 306 { 307 rw_lock_write_lock(&sAddressSpaceTableLock); 308 309 bool remove = false; 310 VMAddressSpace* addressSpace = sAddressSpaceTable.Lookup(id); 311 if (addressSpace != NULL && addressSpace->fRefCount == 0) { 312 sAddressSpaceTable.RemoveUnchecked(addressSpace); 313 remove = true; 314 } 315 316 rw_lock_write_unlock(&sAddressSpaceTableLock); 317 318 if (remove) 319 delete addressSpace; 320 } 321 322 323 /*static*/ int 324 VMAddressSpace::_DumpCommand(int argc, char** argv) 325 { 326 VMAddressSpace* aspace; 327 328 if (argc < 2) { 329 kprintf("aspace: not enough arguments\n"); 330 return 0; 331 } 332 333 // if the argument looks like a number, treat it as such 334 335 { 336 team_id id = strtoul(argv[1], NULL, 0); 337 338 aspace = sAddressSpaceTable.Lookup(id); 339 if (aspace == NULL) { 340 kprintf("invalid aspace id\n"); 341 } else { 342 aspace->Dump(); 343 } 344 } 345 346 return 0; 347 } 348 349 350 /*static*/ int 351 VMAddressSpace::_DumpListCommand(int argc, char** argv) 352 { 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"); 356 357 AddressSpaceTable::Iterator it = sAddressSpaceTable.GetIterator(); 358 while (VMAddressSpace* space = it.Next()) { 359 int32 areaCount = 0; 360 off_t areaSize = 0; 361 for (VMAddressSpace::AreaIterator areaIt = space->GetAreaIterator(); 362 VMArea* area = areaIt.Next();) { 363 areaCount++; 364 areaSize += area->Size(); 365 } 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); 369 } 370 371 return 0; 372 } 373