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 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 /*! Deletes all areas in the specified address space, and the address 141 space by decreasing all reference counters. It also marks the 142 address space of being in deletion state, so that no more areas 143 can be created in it. 144 After this, the address space is not operational anymore, but might 145 still be in memory until the last reference has been released. 146 */ 147 void 148 VMAddressSpace::RemoveAndPut() 149 { 150 WriteLock(); 151 fDeleting = true; 152 WriteUnlock(); 153 154 vm_delete_areas(this, true); 155 Put(); 156 } 157 158 159 status_t 160 VMAddressSpace::InitObject() 161 { 162 return B_OK; 163 } 164 165 166 void 167 VMAddressSpace::Dump() const 168 { 169 kprintf("dump of address space at %p:\n", this); 170 kprintf("id: %" B_PRId32 "\n", fID); 171 kprintf("ref_count: %" B_PRId32 "\n", fRefCount); 172 kprintf("fault_count: %" B_PRId32 "\n", fFaultCount); 173 kprintf("translation_map: %p\n", fTranslationMap); 174 kprintf("base: %#" B_PRIxADDR "\n", fBase); 175 kprintf("end: %#" B_PRIxADDR "\n", fEndAddress); 176 kprintf("change_count: %" B_PRId32 "\n", fChangeCount); 177 } 178 179 180 /*static*/ status_t 181 VMAddressSpace::Create(team_id teamID, addr_t base, size_t size, bool kernel, 182 VMAddressSpace** _addressSpace) 183 { 184 VMAddressSpace* addressSpace = kernel 185 ? (VMAddressSpace*)new(std::nothrow) VMKernelAddressSpace(teamID, base, 186 size) 187 : (VMAddressSpace*)new(std::nothrow) VMUserAddressSpace(teamID, base, 188 size); 189 if (addressSpace == NULL) 190 return B_NO_MEMORY; 191 192 status_t status = addressSpace->InitObject(); 193 if (status != B_OK) { 194 delete addressSpace; 195 return status; 196 } 197 198 TRACE(("VMAddressSpace::Create(): team %ld (%skernel): %#lx bytes starting at " 199 "%#lx => %p\n", teamID, kernel ? "" : "!", size, base, addressSpace)); 200 201 // create the corresponding translation map 202 status = arch_vm_translation_map_create_map(kernel, 203 &addressSpace->fTranslationMap); 204 if (status != B_OK) { 205 delete addressSpace; 206 return status; 207 } 208 209 // add the aspace to the global hash table 210 rw_lock_write_lock(&sAddressSpaceTableLock); 211 sAddressSpaceTable.InsertUnchecked(addressSpace); 212 rw_lock_write_unlock(&sAddressSpaceTableLock); 213 214 *_addressSpace = addressSpace; 215 return B_OK; 216 } 217 218 219 /*static*/ VMAddressSpace* 220 VMAddressSpace::GetKernel() 221 { 222 // we can treat this one a little differently since it can't be deleted 223 sKernelAddressSpace->Get(); 224 return sKernelAddressSpace; 225 } 226 227 228 /*static*/ team_id 229 VMAddressSpace::CurrentID() 230 { 231 Thread* thread = thread_get_current_thread(); 232 233 if (thread != NULL && thread->team->address_space != NULL) 234 return thread->team->id; 235 236 return B_ERROR; 237 } 238 239 240 /*static*/ VMAddressSpace* 241 VMAddressSpace::GetCurrent() 242 { 243 Thread* thread = thread_get_current_thread(); 244 245 if (thread != NULL) { 246 VMAddressSpace* addressSpace = thread->team->address_space; 247 if (addressSpace != NULL) { 248 addressSpace->Get(); 249 return addressSpace; 250 } 251 } 252 253 return NULL; 254 } 255 256 257 /*static*/ VMAddressSpace* 258 VMAddressSpace::Get(team_id teamID) 259 { 260 rw_lock_read_lock(&sAddressSpaceTableLock); 261 VMAddressSpace* addressSpace = sAddressSpaceTable.Lookup(teamID); 262 if (addressSpace) 263 addressSpace->Get(); 264 rw_lock_read_unlock(&sAddressSpaceTableLock); 265 266 return addressSpace; 267 } 268 269 270 /*static*/ VMAddressSpace* 271 VMAddressSpace::DebugFirst() 272 { 273 return sAddressSpaceTable.GetIterator().Next(); 274 } 275 276 277 /*static*/ VMAddressSpace* 278 VMAddressSpace::DebugNext(VMAddressSpace* addressSpace) 279 { 280 if (addressSpace == NULL) 281 return NULL; 282 283 AddressSpaceTable::Iterator it 284 = sAddressSpaceTable.GetIterator(addressSpace->ID()); 285 it.Next(); 286 return it.Next(); 287 } 288 289 290 /*static*/ VMAddressSpace* 291 VMAddressSpace::DebugGet(team_id teamID) 292 { 293 return sAddressSpaceTable.Lookup(teamID); 294 } 295 296 297 /*static*/ void 298 VMAddressSpace::_DeleteIfUnreferenced(team_id id) 299 { 300 rw_lock_write_lock(&sAddressSpaceTableLock); 301 302 bool remove = false; 303 VMAddressSpace* addressSpace = sAddressSpaceTable.Lookup(id); 304 if (addressSpace != NULL && addressSpace->fRefCount == 0) { 305 sAddressSpaceTable.RemoveUnchecked(addressSpace); 306 remove = true; 307 } 308 309 rw_lock_write_unlock(&sAddressSpaceTableLock); 310 311 if (remove) 312 delete addressSpace; 313 } 314 315 316 /*static*/ int 317 VMAddressSpace::_DumpCommand(int argc, char** argv) 318 { 319 VMAddressSpace* aspace; 320 321 if (argc < 2) { 322 kprintf("aspace: not enough arguments\n"); 323 return 0; 324 } 325 326 // if the argument looks like a number, treat it as such 327 328 { 329 team_id id = strtoul(argv[1], NULL, 0); 330 331 aspace = sAddressSpaceTable.Lookup(id); 332 if (aspace == NULL) { 333 kprintf("invalid aspace id\n"); 334 } else { 335 aspace->Dump(); 336 } 337 return 0; 338 } 339 return 0; 340 } 341 342 343 /*static*/ int 344 VMAddressSpace::_DumpListCommand(int argc, char** argv) 345 { 346 kprintf(" address id base end area count " 347 " area size\n"); 348 349 AddressSpaceTable::Iterator it = sAddressSpaceTable.GetIterator(); 350 while (VMAddressSpace* space = it.Next()) { 351 int32 areaCount = 0; 352 off_t areaSize = 0; 353 for (VMAddressSpace::AreaIterator areaIt = space->GetAreaIterator(); 354 VMArea* area = areaIt.Next();) { 355 areaCount++; 356 areaSize += area->Size(); 357 } 358 kprintf("%p %6" B_PRId32 " %#010" B_PRIxADDR " %#10" B_PRIxADDR 359 " %10" B_PRId32 " %10" B_PRIdOFF "\n", space, space->ID(), 360 space->Base(), space->EndAddress(), areaCount, areaSize); 361 } 362 363 return 0; 364 } 365