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