xref: /haiku/src/system/kernel/vm/vm.cpp (revision ea6253d0ba561f923f74af1febaf250d2419b1ae)
1 /*
2  * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  *
5  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
6  * Distributed under the terms of the NewOS License.
7  */
8 
9 
10 #include <OS.h>
11 #include <KernelExport.h>
12 
13 #include <vm.h>
14 #include <vm_priv.h>
15 #include <vm_page.h>
16 #include <vm_cache.h>
17 #include <vm_store_anonymous_noswap.h>
18 #include <vm_store_device.h>
19 #include <vm_store_null.h>
20 #include <vm_low_memory.h>
21 #include <file_cache.h>
22 #include <memheap.h>
23 #include <debug.h>
24 #include <console.h>
25 #include <int.h>
26 #include <smp.h>
27 #include <lock.h>
28 #include <thread.h>
29 #include <team.h>
30 
31 #include <boot/stage2.h>
32 #include <boot/elf.h>
33 
34 #include <arch/cpu.h>
35 #include <arch/vm.h>
36 
37 #include <string.h>
38 #include <ctype.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 
42 //#define TRACE_VM
43 //#define TRACE_FAULTS
44 #ifdef TRACE_VM
45 #	define TRACE(x) dprintf x
46 #else
47 #	define TRACE(x) ;
48 #endif
49 #ifdef TRACE_FAULTS
50 #	define FTRACE(x) dprintf x
51 #else
52 #	define FTRACE(x) ;
53 #endif
54 
55 #define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1))
56 #define ROUNDOWN(a, b) (((a) / (b)) * (b))
57 
58 
59 extern vm_address_space *kernel_aspace;
60 
61 #define REGION_HASH_TABLE_SIZE 1024
62 static area_id sNextAreaID;
63 static hash_table *sAreaHash;
64 static sem_id sAreaHashLock;
65 
66 static off_t sAvailableMemory;
67 static benaphore sAvailableMemoryLock;
68 
69 // function declarations
70 static vm_area *_vm_create_region_struct(vm_address_space *aspace, const char *name, int wiring, int lock);
71 static status_t map_backing_store(vm_address_space *aspace, vm_store *store, void **vaddr,
72 	off_t offset, addr_t size, uint32 addressSpec, int wiring, int lock, int mapping, vm_area **_area, const char *area_name);
73 static status_t vm_soft_fault(addr_t address, bool is_write, bool is_user);
74 static vm_area *vm_virtual_map_lookup(vm_virtual_map *map, addr_t address);
75 static bool vm_put_area(vm_area *area);
76 
77 
78 static int
79 area_compare(void *_area, const void *key)
80 {
81 	vm_area *area = (vm_area *)_area;
82 	const area_id *id = (const area_id *)key;
83 
84 	if (area->id == *id)
85 		return 0;
86 
87 	return -1;
88 }
89 
90 
91 static uint32
92 area_hash(void *_area, const void *key, uint32 range)
93 {
94 	vm_area *area = (vm_area *)_area;
95 	const area_id *id = (const area_id *)key;
96 
97 	if (area != NULL)
98 		return area->id % range;
99 
100 	return *id % range;
101 }
102 
103 
104 static vm_area *
105 vm_get_area(area_id id)
106 {
107 	vm_area *area;
108 
109 	acquire_sem_etc(sAreaHashLock, READ_COUNT, 0, 0);
110 
111 	area = (vm_area *)hash_lookup(sAreaHash, &id);
112 	if (area != NULL)
113 		atomic_add(&area->ref_count, 1);
114 
115 	release_sem_etc(sAreaHashLock, READ_COUNT, 0);
116 
117 	return area;
118 }
119 
120 
121 static vm_area *
122 _vm_create_reserved_region_struct(vm_virtual_map *map, uint32 flags)
123 {
124 	vm_area *reserved = (vm_area *)malloc(sizeof(vm_area));
125 	if (reserved == NULL)
126 		return NULL;
127 
128 	memset(reserved, 0, sizeof(vm_area));
129 	reserved->id = RESERVED_AREA_ID;
130 		// this marks it as reserved space
131 	reserved->protection = flags;
132 	reserved->map = map;
133 
134 	return reserved;
135 }
136 
137 
138 static vm_area *
139 _vm_create_area_struct(vm_address_space *aspace, const char *name, uint32 wiring, uint32 protection)
140 {
141 	vm_area *area = NULL;
142 
143 	// restrict the area name to B_OS_NAME_LENGTH
144 	size_t length = strlen(name) + 1;
145 	if (length > B_OS_NAME_LENGTH)
146 		length = B_OS_NAME_LENGTH;
147 
148 	area = (vm_area *)malloc(sizeof(vm_area));
149 	if (area == NULL)
150 		return NULL;
151 
152 	area->name = (char *)malloc(length);
153 	if (area->name == NULL) {
154 		free(area);
155 		return NULL;
156 	}
157 	strlcpy(area->name, name, length);
158 
159 	area->id = atomic_add(&sNextAreaID, 1);
160 	area->base = 0;
161 	area->size = 0;
162 	area->protection = protection;
163 	area->wiring = wiring;
164 	area->ref_count = 1;
165 
166 	area->cache_ref = NULL;
167 	area->cache_offset = 0;
168 
169 	area->aspace = aspace;
170 	area->aspace_next = NULL;
171 	area->map = &aspace->virtual_map;
172 	area->cache_next = area->cache_prev = NULL;
173 	area->hash_next = NULL;
174 
175 	return area;
176 }
177 
178 
179 /**	Finds a reserved area that covers the region spanned by \a start and
180  *	\a size, inserts the \a area into that region and makes sure that
181  *	there are reserved regions for the remaining parts.
182  */
183 
184 static status_t
185 find_reserved_area(vm_virtual_map *map, addr_t start, addr_t size, vm_area *area)
186 {
187 	vm_area *next, *last = NULL;
188 
189 	next = map->areas;
190 	while (next) {
191 		if (next->base <= start && next->base + next->size >= start + size) {
192 			// this area covers the requested range
193 			if (next->id != RESERVED_AREA_ID) {
194 				// but it's not reserved space, it's a real area
195 				return B_BAD_VALUE;
196 			}
197 
198 			break;
199 		}
200 		last = next;
201 		next = next->aspace_next;
202 	}
203 	if (next == NULL)
204 		return B_ENTRY_NOT_FOUND;
205 
206 	// now we have to transfer the requested part of the reserved
207 	// range to the new area - and remove, resize or split the old
208 	// reserved area.
209 
210 	if (start == next->base) {
211 		// the area starts at the beginning of the reserved range
212 		if (last)
213 			last->aspace_next = area;
214 		else
215 			map->areas = area;
216 
217 		if (size == next->size) {
218 			// the new area fully covers the reversed range
219 			area->aspace_next = next->aspace_next;
220 			free(next);
221 		} else {
222 			// resize the reserved range behind the area
223 			area->aspace_next = next;
224 			next->base += size;
225 			next->size -= size;
226 		}
227 	} else if (start + size == next->base + next->size) {
228 		// the area is at the end of the reserved range
229 		area->aspace_next = next->aspace_next;
230 		next->aspace_next = area;
231 
232 		// resize the reserved range before the area
233 		next->size = start - next->base;
234 	} else {
235 		// the area splits the reserved range into two separate ones
236 		// we need a new reserved area to cover this space
237 		vm_area *reserved = _vm_create_reserved_region_struct(map, next->protection);
238 		if (reserved == NULL)
239 			return B_NO_MEMORY;
240 
241 		reserved->aspace_next = next->aspace_next;
242 		area->aspace_next = reserved;
243 		next->aspace_next = area;
244 
245 		// resize regions
246 		reserved->size = next->base + next->size - start - size;
247 		next->size = start - next->base;
248 		reserved->base = start + size;
249 		reserved->cache_offset = next->cache_offset;
250 	}
251 
252 	area->base = start;
253 	area->size = size;
254 	map->change_count++;
255 
256 	return B_OK;
257 }
258 
259 
260 // must be called with this address space's virtual_map.sem held
261 
262 static status_t
263 find_and_insert_area_slot(vm_virtual_map *map, addr_t start, addr_t size, addr_t end,
264 	uint32 addressSpec, vm_area *area)
265 {
266 	vm_area *last = NULL;
267 	vm_area *next;
268 	bool foundSpot = false;
269 
270 	TRACE(("find_and_insert_region_slot: map %p, start 0x%lx, size %ld, end 0x%lx, addressSpec %ld, area %p\n",
271 		map, start, size, end, addressSpec, area));
272 
273 	// do some sanity checking
274 	if (start < map->base || size == 0
275 		|| (end - 1) > (map->base + (map->size - 1))
276 		|| start + size > end)
277 		return B_BAD_ADDRESS;
278 
279 	if (addressSpec == B_EXACT_ADDRESS) {
280 		// search for a reserved area
281 		status_t status = find_reserved_area(map, start, size, area);
282 		if (status == B_OK || status == B_BAD_VALUE)
283 			return status;
284 
285 		// there was no reserved area, and the slot doesn't seem to be used already
286 		// ToDo: this could be further optimized.
287 	}
288 
289 	// walk up to the spot where we should start searching
290 second_chance:
291 	next = map->areas;
292 	while (next) {
293 		if (next->base >= start + size) {
294 			// we have a winner
295 			break;
296 		}
297 		last = next;
298 		next = next->aspace_next;
299 	}
300 
301 	// find the right spot depending on the address specification - the area
302 	// will be inserted directly after "last" ("next" is not referenced anymore)
303 
304 	switch (addressSpec) {
305 		case B_ANY_ADDRESS:
306 		case B_ANY_KERNEL_ADDRESS:
307 		case B_ANY_KERNEL_BLOCK_ADDRESS:
308 			// find a hole big enough for a new area
309 			if (!last) {
310 				// see if we can build it at the beginning of the virtual map
311 				if (!next || (next->base >= map->base + size)) {
312 					foundSpot = true;
313 					area->base = map->base;
314 					break;
315 				}
316 				last = next;
317 				next = next->aspace_next;
318 			}
319 			// keep walking
320 			while (next) {
321 				if (next->base >= last->base + last->size + size) {
322 					// we found a spot (it'll be filled up below)
323 					break;
324 				}
325 				last = next;
326 				next = next->aspace_next;
327 			}
328 
329 			if ((map->base + (map->size - 1)) >= (last->base + last->size + (size - 1))) {
330 				// got a spot
331 				foundSpot = true;
332 				area->base = last->base + last->size;
333 				break;
334 			} else {
335 				// we didn't find a free spot - if there were any reserved areas with
336 				// the RESERVED_AVOID_BASE flag set, we can now test those for free
337 				// space
338 				// ToDo: it would make sense to start with the biggest of them
339 				next = map->areas;
340 				last = NULL;
341 				for (last = NULL; next; next = next->aspace_next, last = next) {
342 					// ToDo: take free space after the reserved area into account!
343 					if (next->size == size) {
344 						// the reserved area is entirely covered, and thus, removed
345 						if (last)
346 							last->aspace_next = next->aspace_next;
347 						else
348 							map->areas = next->aspace_next;
349 
350 						foundSpot = true;
351 						area->base = next->base;
352 						free(next);
353 						break;
354 					}
355 					if (next->size >= size) {
356 						// the new area will be placed at the end of the reserved
357 						// area, and the reserved area will be resized to make space
358 						foundSpot = true;
359 						next->size -= size;
360 						last = next;
361 						area->base = next->base + next->size;
362 						break;
363 					}
364 				}
365 			}
366 			break;
367 
368 		case B_BASE_ADDRESS:
369 			// find a hole big enough for a new area beginning with "start"
370 			if (!last) {
371 				// see if we can build it at the beginning of the specified start
372 				if (!next || (next->base >= start + size)) {
373 					foundSpot = true;
374 					area->base = start;
375 					break;
376 				}
377 				last = next;
378 				next = next->aspace_next;
379 			}
380 			// keep walking
381 			while (next) {
382 				if (next->base >= last->base + last->size + size) {
383 					// we found a spot (it'll be filled up below)
384 					break;
385 				}
386 				last = next;
387 				next = next->aspace_next;
388 			}
389 
390 			if ((map->base + (map->size - 1)) >= (last->base + last->size + (size - 1))) {
391 				// got a spot
392 				foundSpot = true;
393 				if (last->base + last->size <= start)
394 					area->base = start;
395 				else
396 					area->base = last->base + last->size;
397 				break;
398 			}
399 			// we didn't find a free spot in the requested range, so we'll
400 			// try again without any restrictions
401 			start = map->base;
402 			addressSpec = B_ANY_ADDRESS;
403 			last = NULL;
404 			goto second_chance;
405 
406 		case B_EXACT_ADDRESS:
407 			// see if we can create it exactly here
408 			if (!last) {
409 				if (!next || (next->base >= start + size)) {
410 					foundSpot = true;
411 					area->base = start;
412 					break;
413 				}
414 			} else {
415 				if (next) {
416 					if (last->base + last->size <= start && next->base >= start + size) {
417 						foundSpot = true;
418 						area->base = start;
419 						break;
420 					}
421 				} else {
422 					if ((last->base + (last->size - 1)) <= start - 1) {
423 						foundSpot = true;
424 						area->base = start;
425 					}
426 				}
427 			}
428 			break;
429 		default:
430 			return B_BAD_VALUE;
431 	}
432 
433 	if (!foundSpot)
434 		return addressSpec == B_EXACT_ADDRESS ? B_BAD_VALUE : B_NO_MEMORY;
435 
436 	area->size = size;
437 	if (last) {
438 		area->aspace_next = last->aspace_next;
439 		last->aspace_next = area;
440 	} else {
441 		area->aspace_next = map->areas;
442 		map->areas = area;
443 	}
444 	map->change_count++;
445 	return B_OK;
446 }
447 
448 
449 /**	This inserts the area you pass into the virtual_map of the
450  *	specified address space.
451  *	It will also set the "_address" argument to its base address when
452  *	the call succeeds.
453  *	You need to hold the virtual_map semaphore.
454  */
455 
456 static status_t
457 insert_area(vm_address_space *addressSpace, void **_address,
458 	uint32 addressSpec, addr_t size, vm_area *area)
459 {
460 	addr_t searchBase, searchEnd;
461 	status_t status;
462 
463 	switch (addressSpec) {
464 		case B_EXACT_ADDRESS:
465 			searchBase = (addr_t)*_address;
466 			searchEnd = (addr_t)*_address + size;
467 			break;
468 
469 		case B_BASE_ADDRESS:
470 			searchBase = (addr_t)*_address;
471 			searchEnd = addressSpace->virtual_map.base + (addressSpace->virtual_map.size - 1);
472 			break;
473 
474 		case B_ANY_ADDRESS:
475 		case B_ANY_KERNEL_ADDRESS:
476 		case B_ANY_KERNEL_BLOCK_ADDRESS:
477 			searchBase = addressSpace->virtual_map.base;
478 			searchEnd = addressSpace->virtual_map.base + (addressSpace->virtual_map.size - 1);
479 			break;
480 
481 		default:
482 			return B_BAD_VALUE;
483 	}
484 
485 	status = find_and_insert_area_slot(&addressSpace->virtual_map, searchBase, size,
486 				searchEnd, addressSpec, area);
487 	if (status == B_OK)
488 		// ToDo: do we have to do anything about B_ANY_KERNEL_ADDRESS
489 		//		vs. B_ANY_KERNEL_BLOCK_ADDRESS here?
490 		*_address = (void *)area->base;
491 
492 	return status;
493 }
494 
495 
496 // a ref to the cache holding this store must be held before entering here
497 static status_t
498 map_backing_store(vm_address_space *aspace, vm_store *store, void **_virtualAddress,
499 	off_t offset, addr_t size, uint32 addressSpec, int wiring, int protection,
500 	int mapping, vm_area **_area, const char *areaName)
501 {
502 	vm_cache *cache;
503 	vm_cache_ref *cache_ref;
504 	vm_area *area;
505 	vm_cache *nu_cache;
506 	vm_cache_ref *nu_cache_ref = NULL;
507 	vm_store *nu_store;
508 
509 	int err;
510 
511 	TRACE(("map_backing_store: aspace %p, store %p, *vaddr %p, offset 0x%Lx, size %lu, addressSpec %ld, wiring %d, protection %d, _area %p, area_name '%s'\n",
512 		aspace, store, *_virtualAddress, offset, size, addressSpec, wiring, protection, _area, areaName));
513 
514 	area = _vm_create_area_struct(aspace, areaName, wiring, protection);
515 	if (area == NULL)
516 		return B_NO_MEMORY;
517 
518 	cache = store->cache;
519 	cache_ref = cache->ref;
520 
521 	// if this is a private map, we need to create a new cache & store object
522 	// pair to handle the private copies of pages as they are written to
523 	if (mapping == REGION_PRIVATE_MAP) {
524 		// create an anonymous store object
525 		nu_store = vm_store_create_anonymous_noswap((protection & B_STACK_AREA) != 0, USER_STACK_GUARD_PAGES);
526 		if (nu_store == NULL)
527 			panic("map_backing_store: vm_create_store_anonymous_noswap returned NULL");
528 		nu_cache = vm_cache_create(nu_store);
529 		if (nu_cache == NULL)
530 			panic("map_backing_store: vm_cache_create returned NULL");
531 		nu_cache_ref = vm_cache_ref_create(nu_cache);
532 		if (nu_cache_ref == NULL)
533 			panic("map_backing_store: vm_cache_ref_create returned NULL");
534 		nu_cache->temporary = 1;
535 		nu_cache->scan_skip = cache->scan_skip;
536 
537 		nu_cache->source = cache;
538 
539 		// grab a ref to the cache object we're now linked to as a source
540 		vm_cache_acquire_ref(cache_ref, true);
541 
542 		cache = nu_cache;
543 		cache_ref = cache->ref;
544 		store = nu_store;
545 		cache->virtual_size = offset + size;
546 	}
547 
548 	err = vm_cache_set_minimal_commitment(cache_ref, offset + size);
549 	if (err != B_OK)
550 		goto err1a;
551 
552 	vm_cache_acquire_ref(cache_ref, true);
553 
554 	acquire_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0, 0);
555 
556 	// check to see if this aspace has entered DELETE state
557 	if (aspace->state == VM_ASPACE_STATE_DELETION) {
558 		// okay, someone is trying to delete this aspace now, so we can't
559 		// insert the area, so back out
560 		err = B_BAD_TEAM_ID;
561 		goto err1b;
562 	}
563 
564 	err = insert_area(aspace, _virtualAddress, addressSpec, size, area);
565 	if (err < B_OK)
566 		goto err1b;
567 
568 	// attach the cache to the area
569 	area->cache_ref = cache_ref;
570 	area->cache_offset = offset;
571 	// point the cache back to the area
572 	vm_cache_insert_area(cache_ref, area);
573 
574 	// insert the area in the global area hash table
575 	acquire_sem_etc(sAreaHashLock, WRITE_COUNT, 0 ,0);
576 	hash_insert(sAreaHash, area);
577 	release_sem_etc(sAreaHashLock, WRITE_COUNT, 0);
578 
579 	// grab a ref to the aspace (the area holds this)
580 	atomic_add(&aspace->ref_count, 1);
581 
582 	release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0);
583 
584 	*_area = area;
585 	return B_OK;
586 
587 err1b:
588 	release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0);
589 	vm_cache_release_ref(cache_ref);
590 	goto err;
591 err1a:
592 	if (nu_cache_ref) {
593 		// had never acquired it's initial ref, so acquire and then release it
594 		// this should clean up all the objects it references
595 		vm_cache_acquire_ref(cache_ref, true);
596 		vm_cache_release_ref(cache_ref);
597 	}
598 err:
599 	free(area->name);
600 	free(area);
601 	return err;
602 }
603 
604 
605 status_t
606 vm_unreserve_address_range(aspace_id aid, void *address, addr_t size)
607 {
608 	vm_address_space *addressSpace;
609 	vm_area *area, *last = NULL;
610 	status_t status = B_OK;
611 
612 	addressSpace = vm_get_aspace_by_id(aid);
613 	if (addressSpace == NULL)
614 		return B_BAD_TEAM_ID;
615 
616 	acquire_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0, 0);
617 
618 	// check to see if this aspace has entered DELETE state
619 	if (addressSpace->state == VM_ASPACE_STATE_DELETION) {
620 		// okay, someone is trying to delete this aspace now, so we can't
621 		// insert the area, so back out
622 		status = B_BAD_TEAM_ID;
623 		goto out;
624 	}
625 
626 	// search area list and remove any matching reserved ranges
627 
628 	area = addressSpace->virtual_map.areas;
629 	while (area) {
630 		// the area must be completely part of the reserved range
631 		if (area->id == RESERVED_AREA_ID && area->base >= (addr_t)address
632 			&& area->base + area->size <= (addr_t)address + size) {
633 			// remove reserved range
634 			vm_area *reserved = area;
635 			if (last)
636 				last->aspace_next = reserved->aspace_next;
637 			else
638 				addressSpace->virtual_map.areas = reserved->aspace_next;
639 
640 			area = reserved->aspace_next;
641 			free(reserved);
642 			continue;
643 		}
644 
645 		last = area;
646 		area = area->aspace_next;
647 	}
648 
649 out:
650 	release_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0);
651 	vm_put_aspace(addressSpace);
652 	return status;
653 }
654 
655 
656 status_t
657 vm_reserve_address_range(aspace_id aid, void **_address, uint32 addressSpec,
658 	addr_t size, uint32 flags)
659 {
660 	vm_address_space *addressSpace;
661 	vm_area *area;
662 	status_t status = B_OK;
663 
664 	if (size == 0)
665 		return B_BAD_VALUE;
666 
667 	addressSpace = vm_get_aspace_by_id(aid);
668 	if (addressSpace == NULL)
669 		return B_BAD_TEAM_ID;
670 
671 	area = _vm_create_reserved_region_struct(&addressSpace->virtual_map, flags);
672 	if (area == NULL) {
673 		status = B_NO_MEMORY;
674 		goto err1;
675 	}
676 
677 	acquire_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0, 0);
678 
679 	// check to see if this aspace has entered DELETE state
680 	if (addressSpace->state == VM_ASPACE_STATE_DELETION) {
681 		// okay, someone is trying to delete this aspace now, so we can't
682 		// insert the area, let's back out
683 		status = B_BAD_TEAM_ID;
684 		goto err2;
685 	}
686 
687 	status = insert_area(addressSpace, _address, addressSpec, size, area);
688 	if (status < B_OK)
689 		goto err2;
690 
691 	// the area is now reserved!
692 
693 	area->cache_offset = area->base;
694 		// we cache the original base address here
695 
696 	release_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0);
697 	return B_OK;
698 
699 err2:
700 	release_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0);
701 	free(area);
702 err1:
703 	vm_put_aspace(addressSpace);
704 	return status;
705 }
706 
707 
708 area_id
709 vm_create_anonymous_area(aspace_id aid, const char *name, void **address,
710 	uint32 addressSpec, addr_t size, uint32 wiring, uint32 protection)
711 {
712 	vm_area *area;
713 	vm_cache *cache;
714 	vm_store *store;
715 	vm_address_space *aspace;
716 	vm_cache_ref *cache_ref;
717 	vm_page *page = NULL;
718 	bool isStack = (protection & B_STACK_AREA) != 0;
719 	bool canOvercommit = false;
720 	status_t err;
721 
722 	TRACE(("create_anonymous_area %s: size 0x%lx\n", name, size));
723 
724 	if (!arch_vm_supports_protection(protection))
725 		return B_NOT_SUPPORTED;
726 
727 	if (isStack || (protection & B_OVERCOMMITTING_AREA) != 0)
728 		canOvercommit = true;
729 
730 #ifdef DEBUG_KERNEL_STACKS
731 	if ((protection & B_KERNEL_STACK_AREA) != 0)
732 		isStack = true;
733 #endif
734 
735 	/* check parameters */
736 	switch (addressSpec) {
737 		case B_ANY_ADDRESS:
738 		case B_EXACT_ADDRESS:
739 		case B_BASE_ADDRESS:
740 		case B_ANY_KERNEL_ADDRESS:
741 			break;
742 
743 		default:
744 			return B_BAD_VALUE;
745 	}
746 
747 	switch (wiring) {
748 		case B_NO_LOCK:
749 		case B_FULL_LOCK:
750 		case B_LAZY_LOCK:
751 		case B_CONTIGUOUS:
752 		case B_ALREADY_WIRED:
753 			break;
754 		case B_LOMEM:
755 		//case B_SLOWMEM:
756 			dprintf("B_LOMEM/SLOWMEM is not yet supported!\n");
757 			wiring = B_FULL_LOCK;
758 			break;
759 		default:
760 			return B_BAD_VALUE;
761 	}
762 
763 	aspace = vm_get_aspace_by_id(aid);
764 	if (aspace == NULL)
765 		return B_BAD_TEAM_ID;
766 
767 	size = PAGE_ALIGN(size);
768 
769 	if (wiring == B_CONTIGUOUS) {
770 		// we try to allocate the page run here upfront as this may easily fail for obvious reasons
771 		page = vm_page_allocate_page_run(PAGE_STATE_CLEAR, size / B_PAGE_SIZE);
772 		if (page == NULL) {
773 			vm_put_aspace(aspace);
774 			return B_NO_MEMORY;
775 		}
776 	}
777 
778 	// create an anonymous store object
779 	store = vm_store_create_anonymous_noswap(canOvercommit, isStack ?
780 		((protection & B_USER_PROTECTION) != 0 ?
781 			USER_STACK_GUARD_PAGES : KERNEL_STACK_GUARD_PAGES) : 0);
782 	if (store == NULL)
783 		panic("vm_create_anonymous_area: vm_create_store_anonymous_noswap returned NULL");
784 	cache = vm_cache_create(store);
785 	if (cache == NULL)
786 		panic("vm_create_anonymous_area: vm_cache_create returned NULL");
787 	cache_ref = vm_cache_ref_create(cache);
788 	if (cache_ref == NULL)
789 		panic("vm_create_anonymous_area: vm_cache_ref_create returned NULL");
790 	cache->temporary = 1;
791 
792 	switch (wiring) {
793 		case B_LAZY_LOCK:	// for now
794 		case B_FULL_LOCK:
795 		case B_CONTIGUOUS:
796 		case B_ALREADY_WIRED:
797 			cache->scan_skip = 1;
798 			break;
799 		case B_NO_LOCK:
800 		//case B_LAZY_LOCK:
801 			cache->scan_skip = 0;
802 			break;
803 	}
804 
805 	vm_cache_acquire_ref(cache_ref, true);
806 	err = map_backing_store(aspace, store, address, 0, size, addressSpec, wiring, protection, REGION_NO_PRIVATE_MAP, &area, name);
807 	vm_cache_release_ref(cache_ref);
808 	if (err < 0) {
809 		vm_put_aspace(aspace);
810 
811 		if (wiring == B_CONTIGUOUS) {
812 			// we had reserved the area space upfront...
813 			addr_t pageNumber = page->ppn;
814 			int32 i;
815 			for (i = size / B_PAGE_SIZE; i-- > 0; pageNumber++) {
816 				page = vm_lookup_page(pageNumber);
817 				if (page == NULL)
818 					panic("couldn't lookup physical page just allocated\n");
819 
820 				vm_page_set_state(page, PAGE_STATE_FREE);
821 			}
822 		}
823 		return err;
824 	}
825 
826 	cache_ref = store->cache->ref;
827 	switch (wiring) {
828 		case B_NO_LOCK:
829 		case B_LAZY_LOCK:
830 			break; // do nothing
831 
832 		case B_FULL_LOCK:
833 		{
834 			// Pages aren't mapped at this point, but we just simulate a fault on
835 			// every page, which should allocate them
836 			// ToDo: at this point, it would probably be cheaper to allocate
837 			// and map the pages directly
838 			addr_t va;
839 			for (va = area->base; va < area->base + area->size; va += B_PAGE_SIZE) {
840 #ifdef DEBUG_KERNEL_STACKS
841 #	ifdef STACK_GROWS_DOWNWARDS
842 				if (isStack && va < area->base + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE)
843 #	else
844 				if (isStack && va >= area->base + area->size - KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE)
845 #	endif
846 					continue;
847 #endif
848 				vm_soft_fault(va, false, false);
849 			}
850 			break;
851 		}
852 
853 		case B_ALREADY_WIRED:
854 		{
855 			// the pages should already be mapped. This is only really useful during
856 			// boot time. Find the appropriate vm_page objects and stick them in
857 			// the cache object.
858 			addr_t va;
859 			addr_t pa;
860 			uint32 flags;
861 			int err;
862 			off_t offset = 0;
863 
864 			if (!kernel_startup)
865 				panic("ALREADY_WIRED flag used outside kernel startup\n");
866 
867 			mutex_lock(&cache_ref->lock);
868 			(*aspace->translation_map.ops->lock)(&aspace->translation_map);
869 			for (va = area->base; va < area->base + area->size; va += B_PAGE_SIZE, offset += B_PAGE_SIZE) {
870 				err = (*aspace->translation_map.ops->query)(&aspace->translation_map, va, &pa, &flags);
871 				if (err < 0) {
872 //					dprintf("vm_create_anonymous_area: error looking up mapping for va 0x%x\n", va);
873 					continue;
874 				}
875 				page = vm_lookup_page(pa / B_PAGE_SIZE);
876 				if (page == NULL) {
877 //					dprintf("vm_create_anonymous_area: error looking up vm_page structure for pa 0x%x\n", pa);
878 					continue;
879 				}
880 				atomic_add(&page->ref_count, 1);
881 				vm_page_set_state(page, PAGE_STATE_WIRED);
882 				vm_cache_insert_page(cache_ref, page, offset);
883 			}
884 			(*aspace->translation_map.ops->unlock)(&aspace->translation_map);
885 			mutex_unlock(&cache_ref->lock);
886 			break;
887 		}
888 
889 		case B_CONTIGUOUS:
890 		{
891 			addr_t physicalAddress = page->ppn * B_PAGE_SIZE;
892 			addr_t virtualAddress;
893 			off_t offset = 0;
894 
895 			mutex_lock(&cache_ref->lock);
896 			(*aspace->translation_map.ops->lock)(&aspace->translation_map);
897 
898 			for (virtualAddress = area->base; virtualAddress < area->base + area->size;
899 					virtualAddress += B_PAGE_SIZE, offset += B_PAGE_SIZE, physicalAddress += B_PAGE_SIZE) {
900 				page = vm_lookup_page(physicalAddress / B_PAGE_SIZE);
901 				if (page == NULL)
902 					panic("couldn't lookup physical page just allocated\n");
903 
904 				atomic_add(&page->ref_count, 1);
905 				err = (*aspace->translation_map.ops->map)(&aspace->translation_map,
906 							virtualAddress, physicalAddress, protection);
907 				if (err < 0)
908 					panic("couldn't map physical page in page run\n");
909 
910 				vm_page_set_state(page, PAGE_STATE_WIRED);
911 				vm_cache_insert_page(cache_ref, page, offset);
912 			}
913 
914 			(*aspace->translation_map.ops->unlock)(&aspace->translation_map);
915 			mutex_unlock(&cache_ref->lock);
916 			break;
917 		}
918 
919 		default:
920 			break;
921 	}
922 	vm_put_aspace(aspace);
923 
924 	TRACE(("vm_create_anonymous_area: done\n"));
925 
926 	if (area == NULL)
927 		return B_NO_MEMORY;
928 
929 	return area->id;
930 }
931 
932 
933 area_id
934 vm_map_physical_memory(aspace_id aid, const char *name, void **_address,
935 	uint32 addressSpec, addr_t size, uint32 protection, addr_t phys_addr)
936 {
937 	vm_area *area;
938 	vm_cache *cache;
939 	vm_cache_ref *cache_ref;
940 	vm_store *store;
941 	addr_t map_offset;
942 	int err;
943 	vm_address_space *aspace = vm_get_aspace_by_id(aid);
944 
945 	TRACE(("vm_map_physical_memory(aspace = %ld, \"%s\", virtual = %p, spec = %ld,"
946 		" size = %lu, protection = %ld, phys = %p)\n",
947 		aid, name, _address, addressSpec, size, protection, (void *)phys_addr));
948 
949 	if (!arch_vm_supports_protection(protection))
950 		return B_NOT_SUPPORTED;
951 
952 	if (aspace == NULL)
953 		return B_BAD_TEAM_ID;
954 
955 	// if the physical address is somewhat inside a page,
956 	// move the actual area down to align on a page boundary
957 	map_offset = phys_addr % B_PAGE_SIZE;
958 	size += map_offset;
959 	phys_addr -= map_offset;
960 
961 	size = PAGE_ALIGN(size);
962 
963 	// create an device store object
964 	store = vm_store_create_device(phys_addr);
965 	if (store == NULL)
966 		panic("vm_map_physical_memory: vm_store_create_device returned NULL");
967 	cache = vm_cache_create(store);
968 	if (cache == NULL)
969 		panic("vm_map_physical_memory: vm_cache_create returned NULL");
970 	cache_ref = vm_cache_ref_create(cache);
971 	if (cache_ref == NULL)
972 		panic("vm_map_physical_memory: vm_cache_ref_create returned NULL");
973 	// tell the page scanner to skip over this area, it's pages are special
974 	cache->scan_skip = 1;
975 
976 	vm_cache_acquire_ref(cache_ref, true);
977 	err = map_backing_store(aspace, store, _address, 0, size, addressSpec, 0, protection, REGION_NO_PRIVATE_MAP, &area, name);
978 	vm_cache_release_ref(cache_ref);
979 	vm_put_aspace(aspace);
980 	if (err < 0)
981 		return err;
982 
983 	// modify the pointer returned to be offset back into the new area
984 	// the same way the physical address in was offset
985 	*_address = (void *)((addr_t)*_address + map_offset);
986 
987 	return area->id;
988 }
989 
990 
991 area_id
992 vm_create_null_area(aspace_id aid, const char *name, void **address, uint32 addressSpec, addr_t size)
993 {
994 	vm_area *area;
995 	vm_cache *cache;
996 	vm_cache_ref *cache_ref;
997 	vm_store *store;
998 //	addr_t map_offset;
999 	int err;
1000 
1001 	vm_address_space *aspace = vm_get_aspace_by_id(aid);
1002 	if (aspace == NULL)
1003 		return B_BAD_TEAM_ID;
1004 
1005 	size = PAGE_ALIGN(size);
1006 
1007 	// create an null store object
1008 	store = vm_store_create_null();
1009 	if (store == NULL)
1010 		panic("vm_map_physical_memory: vm_store_create_null returned NULL");
1011 	cache = vm_cache_create(store);
1012 	if (cache == NULL)
1013 		panic("vm_map_physical_memory: vm_cache_create returned NULL");
1014 	cache_ref = vm_cache_ref_create(cache);
1015 	if (cache_ref == NULL)
1016 		panic("vm_map_physical_memory: vm_cache_ref_create returned NULL");
1017 	// tell the page scanner to skip over this area, no pages will be mapped here
1018 	cache->scan_skip = 1;
1019 
1020 	vm_cache_acquire_ref(cache_ref, true);
1021 	err = map_backing_store(aspace, store, address, 0, size, addressSpec, 0, B_KERNEL_READ_AREA, REGION_NO_PRIVATE_MAP, &area, name);
1022 	vm_cache_release_ref(cache_ref);
1023 	vm_put_aspace(aspace);
1024 	if (err < 0)
1025 		return err;
1026 
1027 	return area->id;
1028 }
1029 
1030 
1031 status_t
1032 vm_create_vnode_cache(void *vnode, struct vm_cache_ref **_cacheRef)
1033 {
1034 	vm_cache_ref *cacheRef;
1035 	vm_cache *cache;
1036 	vm_store *store;
1037 
1038 	// create a vnode store object
1039 	store = vm_create_vnode_store(vnode);
1040 	if (store == NULL) {
1041 		dprintf("vm_create_vnode_cache: couldn't create vnode store\n");
1042 		return B_NO_MEMORY;
1043 	}
1044 
1045 	cache = vm_cache_create(store);
1046 	if (cache == NULL) {
1047 		dprintf("vm_create_vnode_cache: vm_cache_create returned NULL\n");
1048 		return B_NO_MEMORY;
1049 	}
1050 
1051 	cacheRef = vm_cache_ref_create(cache);
1052 	if (cacheRef == NULL) {
1053 		dprintf("vm_create_vnode_cache: vm_cache_ref_create returned NULL\n");
1054 		return B_NO_MEMORY;
1055 	}
1056 
1057 	// acquire the cache ref once to represent the ref that the vnode will have
1058 	// this is one of the only places where we dont want to ref to ripple down to the store
1059 	vm_cache_acquire_ref(cacheRef, false);
1060 
1061 	*_cacheRef = cacheRef;
1062 	return B_OK;
1063 }
1064 
1065 
1066 /** Will map the file at the path specified by \a name to an area in memory.
1067  *	The file will be mirrored beginning at the specified \a offset. The \a offset
1068  *	and \a size arguments have to be page aligned.
1069  */
1070 
1071 static area_id
1072 _vm_map_file(aspace_id aid, const char *name, void **_address, uint32 addressSpec,
1073 	size_t size, uint32 protection, uint32 mapping, const char *path, off_t offset, bool kernel)
1074 {
1075 	vm_cache_ref *cacheRef;
1076 	vm_area *area;
1077 	void *vnode;
1078 	status_t status;
1079 
1080 	// ToDo: maybe attach to an FD, not a path (or both, like VFS calls)
1081 	// ToDo: check file access permissions (would be already done if the above were true)
1082 	// ToDo: for binary files, we want to make sure that they get the
1083 	//	copy of a file at a given time, ie. later changes should not
1084 	//	make it into the mapped copy -- this will need quite some changes
1085 	//	to be done in a nice way
1086 
1087 	vm_address_space *aspace = vm_get_aspace_by_id(aid);
1088 	if (aspace == NULL)
1089 		return B_BAD_TEAM_ID;
1090 
1091 	TRACE(("_vm_map_file(\"%s\", offset = %Ld, size = %lu, mapping %ld)\n", path, offset, size, mapping));
1092 
1093 	offset = ROUNDOWN(offset, B_PAGE_SIZE);
1094 	size = PAGE_ALIGN(size);
1095 
1096 	// get the vnode for the object, this also grabs a ref to it
1097 	status = vfs_get_vnode_from_path(path, kernel, &vnode);
1098 	if (status < B_OK)
1099 		goto err1;
1100 
1101 	status = vfs_get_vnode_cache(vnode, &cacheRef);
1102 	if (status < B_OK)
1103 		goto err2;
1104 
1105 	// acquire a ref to the cache before we do work on it. Dont ripple the ref acquision to the vnode
1106 	// below because we'll have to release it later anyway, since we grabbed a ref to the vnode at
1107 	// vfs_get_vnode_from_path(). This puts the ref counts in sync.
1108 	vm_cache_acquire_ref(cacheRef, false);
1109 	status = map_backing_store(aspace, cacheRef->cache->store, _address, offset, size,
1110 					addressSpec, 0, protection, mapping, &area, name);
1111 	vm_cache_release_ref(cacheRef);
1112 	vm_put_aspace(aspace);
1113 
1114 	if (status < B_OK)
1115 		return status;
1116 
1117 	return area->id;
1118 
1119 err2:
1120 	vfs_vnode_release_ref(vnode);
1121 err1:
1122 	vm_put_aspace(aspace);
1123 	return status;
1124 }
1125 
1126 
1127 area_id
1128 vm_map_file(aspace_id aid, const char *name, void **address, uint32 addressSpec,
1129 	addr_t size, uint32 protection, uint32 mapping, const char *path, off_t offset)
1130 {
1131 	if (!arch_vm_supports_protection(protection))
1132 		return B_NOT_SUPPORTED;
1133 
1134 	return _vm_map_file(aid, name, address, addressSpec, size, protection, mapping, path, offset, true);
1135 }
1136 
1137 
1138 // ToDo: create a BeOS style call for this!
1139 
1140 area_id
1141 _user_vm_map_file(const char *uname, void **uaddress, int addressSpec,
1142 	addr_t size, int protection, int mapping, const char *upath, off_t offset)
1143 {
1144 	char name[B_OS_NAME_LENGTH];
1145 	char path[B_PATH_NAME_LENGTH];
1146 	void *address;
1147 	int rc;
1148 
1149 	if (!IS_USER_ADDRESS(uname) || !IS_USER_ADDRESS(uaddress) || !IS_USER_ADDRESS(upath)
1150 		|| user_strlcpy(name, uname, B_OS_NAME_LENGTH) < B_OK
1151 		|| user_strlcpy(path, upath, B_PATH_NAME_LENGTH) < B_OK
1152 		|| user_memcpy(&address, uaddress, sizeof(address)) < B_OK)
1153 		return B_BAD_ADDRESS;
1154 
1155 	// userland created areas can always be accessed by the kernel
1156 	protection |= B_KERNEL_READ_AREA | (protection & B_WRITE_AREA ? B_KERNEL_WRITE_AREA : 0);
1157 
1158 	rc = _vm_map_file(vm_get_current_user_aspace_id(), name, &address, addressSpec, size,
1159 			protection, mapping, path, offset, false);
1160 	if (rc < 0)
1161 		return rc;
1162 
1163 	if (user_memcpy(uaddress, &address, sizeof(address)) < B_OK)
1164 		return B_BAD_ADDRESS;
1165 
1166 	return rc;
1167 }
1168 
1169 
1170 area_id
1171 vm_clone_area(aspace_id aid, const char *name, void **address, uint32 addressSpec,
1172 	uint32 protection, uint32 mapping, area_id sourceID)
1173 {
1174 	vm_area *newArea = NULL;
1175 	vm_area *sourceArea;
1176 	status_t status;
1177 
1178 	vm_address_space *aspace = vm_get_aspace_by_id(aid);
1179 	if (aspace == NULL)
1180 		return B_BAD_TEAM_ID;
1181 
1182 	sourceArea = vm_get_area(sourceID);
1183 	if (sourceArea == NULL) {
1184 		vm_put_aspace(aspace);
1185 		return B_BAD_VALUE;
1186 	}
1187 
1188 	// ToDo: for now, B_USER_CLONEABLE is disabled, until all drivers
1189 	//	have been adapted. Maybe it should be part of the kernel settings,
1190 	//	anyway (so that old drivers can always work).
1191 #if 0
1192 	if (sourceArea->aspace == kernel_aspace && aspace != kernel_aspace
1193 		&& !(sourceArea->protection & B_USER_CLONEABLE_AREA)) {
1194 		// kernel areas must not be cloned in userland, unless explicitly
1195 		// declared user-cloneable upon construction
1196 		status = B_NOT_ALLOWED;
1197 	} else
1198 #endif
1199 	{
1200 		vm_cache_acquire_ref(sourceArea->cache_ref, true);
1201 		status = map_backing_store(aspace, sourceArea->cache_ref->cache->store, address,
1202 					sourceArea->cache_offset, sourceArea->size, addressSpec, sourceArea->wiring,
1203 					protection, mapping, &newArea, name);
1204 		vm_cache_release_ref(sourceArea->cache_ref);
1205 	}
1206 
1207 	vm_put_area(sourceArea);
1208 	vm_put_aspace(aspace);
1209 
1210 	if (status < B_OK)
1211 		return status;
1212 
1213 	return newArea->id;
1214 }
1215 
1216 
1217 static status_t
1218 _vm_delete_area(vm_address_space *aspace, area_id id)
1219 {
1220 	status_t status = B_OK;
1221 	vm_area *area;
1222 
1223 	TRACE(("vm_delete_area: aspace id 0x%lx, area id 0x%lx\n", aspace->id, id));
1224 
1225 	area = vm_get_area(id);
1226 	if (area == NULL)
1227 		return B_BAD_VALUE;
1228 
1229 	if (area->aspace == aspace) {
1230 		vm_put_area(area);
1231 			// next put below will actually delete it
1232 	} else
1233 		status = B_NOT_ALLOWED;
1234 
1235 	vm_put_area(area);
1236 	return status;
1237 }
1238 
1239 
1240 status_t
1241 vm_delete_area(aspace_id aid, area_id rid)
1242 {
1243 	vm_address_space *aspace;
1244 	status_t err;
1245 
1246 	aspace = vm_get_aspace_by_id(aid);
1247 	if (aspace == NULL)
1248 		return B_BAD_TEAM_ID;
1249 
1250 	err = _vm_delete_area(aspace, rid);
1251 	vm_put_aspace(aspace);
1252 	return err;
1253 }
1254 
1255 
1256 static void
1257 remove_area_from_virtual_map(vm_address_space *addressSpace, vm_area *area, bool locked)
1258 {
1259 	vm_area *temp, *last = NULL;
1260 
1261 	if (!locked)
1262 		acquire_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0, 0);
1263 
1264 	temp = addressSpace->virtual_map.areas;
1265 	while (temp != NULL) {
1266 		if (area == temp) {
1267 			if (last != NULL) {
1268 				last->aspace_next = temp->aspace_next;
1269 			} else {
1270 				addressSpace->virtual_map.areas = temp->aspace_next;
1271 			}
1272 			addressSpace->virtual_map.change_count++;
1273 			break;
1274 		}
1275 		last = temp;
1276 		temp = temp->aspace_next;
1277 	}
1278 	if (area == addressSpace->virtual_map.area_hint)
1279 		addressSpace->virtual_map.area_hint = NULL;
1280 
1281 	if (!locked)
1282 		release_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0);
1283 
1284 	if (temp == NULL)
1285 		panic("vm_area_release_ref: area not found in aspace's area list\n");
1286 }
1287 
1288 
1289 static bool
1290 _vm_put_area(vm_area *area, bool aspaceLocked)
1291 {
1292 	vm_address_space *aspace;
1293 	bool removeit = false;
1294 
1295 	// we should never get here, but if we do, we can handle it
1296 	if (area->id == RESERVED_AREA_ID)
1297 		return false;
1298 
1299 	acquire_sem_etc(sAreaHashLock, WRITE_COUNT, 0, 0);
1300 	if (atomic_add(&area->ref_count, -1) == 1) {
1301 		hash_remove(sAreaHash, area);
1302 		removeit = true;
1303 	}
1304 	release_sem_etc(sAreaHashLock, WRITE_COUNT, 0);
1305 
1306 	if (!removeit)
1307 		return false;
1308 
1309 	aspace = area->aspace;
1310 
1311 	remove_area_from_virtual_map(aspace, area, aspaceLocked);
1312 
1313 	vm_cache_remove_area(area->cache_ref, area);
1314 	vm_cache_release_ref(area->cache_ref);
1315 
1316 	(*aspace->translation_map.ops->lock)(&aspace->translation_map);
1317 	(*aspace->translation_map.ops->unmap)(&aspace->translation_map, area->base,
1318 		area->base + (area->size - 1));
1319 	(*aspace->translation_map.ops->unlock)(&aspace->translation_map);
1320 
1321 	// now we can give up the area's reference to the address space
1322 	vm_put_aspace(aspace);
1323 
1324 	free(area->name);
1325 	free(area);
1326 	return true;
1327 }
1328 
1329 
1330 static bool
1331 vm_put_area(vm_area *area)
1332 {
1333 	return _vm_put_area(area, false);
1334 }
1335 
1336 
1337 static status_t
1338 vm_copy_on_write_area(vm_area *area)
1339 {
1340 	vm_store *store;
1341 	vm_cache *upperCache, *lowerCache;
1342 	vm_cache_ref *upperCacheRef, *lowerCacheRef;
1343 	vm_translation_map *map;
1344 	vm_page *page;
1345 	uint32 protection;
1346 	status_t status;
1347 
1348 	TRACE(("vm_copy_on_write_area(area = %p)\n", area));
1349 
1350 	// We need to separate the vm_cache from its vm_cache_ref: the area
1351 	// and its cache_ref goes into a new layer on top of the old one.
1352 	// So the old cache gets a new cache_ref and the area a new cache.
1353 
1354 	upperCacheRef = area->cache_ref;
1355 	lowerCache = upperCacheRef->cache;
1356 
1357 	// create an anonymous store object
1358 	store = vm_store_create_anonymous_noswap(false, 0);
1359 	if (store == NULL)
1360 		return B_NO_MEMORY;
1361 
1362 	upperCache = vm_cache_create(store);
1363 	if (upperCache == NULL) {
1364 		status = B_NO_MEMORY;
1365 		goto err1;
1366 	}
1367 
1368 	lowerCacheRef = vm_cache_ref_create(lowerCache);
1369 	if (lowerCacheRef == NULL) {
1370 		status = B_NO_MEMORY;
1371 		goto err2;
1372 	}
1373 
1374 	// The area must be readable in the same way it was previously writable
1375 	protection = B_KERNEL_READ_AREA;
1376 	if (area->protection & B_READ_AREA)
1377 		protection |= B_READ_AREA;
1378 
1379 	// we need to hold the cache_ref lock when we want to switch its cache
1380 	mutex_lock(&upperCacheRef->lock);
1381 	mutex_lock(&lowerCacheRef->lock);
1382 
1383 	// ToDo: add a child counter to vm_cache - so that we can collapse a
1384 	//		cache layer when possible (ie. "the other" area was deleted)
1385 	upperCache->temporary = 1;
1386 	upperCache->scan_skip = lowerCache->scan_skip;
1387 	upperCache->source = lowerCache;
1388 	upperCache->ref = upperCacheRef;
1389 	upperCacheRef->cache = upperCache;
1390 
1391 	// we need to manually alter the ref_count
1392 	lowerCacheRef->ref_count = upperCacheRef->ref_count;
1393 	upperCacheRef->ref_count = 1;
1394 
1395 	// grab a ref to the cache object we're now linked to as a source
1396 	vm_cache_acquire_ref(lowerCacheRef, true);
1397 
1398 	// We now need to remap all pages from the area read-only, so that
1399 	// a copy will be created on next write access
1400 
1401 	map = &area->aspace->translation_map;
1402 	map->ops->lock(map);
1403 	map->ops->unmap(map, area->base, area->base + area->size - 1);
1404 
1405 	for (page = lowerCache->page_list; page; page = page->cache_next) {
1406 		map->ops->map(map, area->base + page->offset, page->ppn * B_PAGE_SIZE, protection);
1407 	}
1408 
1409 	map->ops->unlock(map);
1410 
1411 	mutex_unlock(&lowerCacheRef->lock);
1412 	mutex_unlock(&upperCacheRef->lock);
1413 
1414 	return B_OK;
1415 
1416 err2:
1417 	free(upperCache);
1418 err1:
1419 	store->ops->destroy(store);
1420 	return status;
1421 }
1422 
1423 
1424 area_id
1425 vm_copy_area(aspace_id addressSpaceID, const char *name, void **_address, uint32 addressSpec,
1426 	uint32 protection, area_id sourceID)
1427 {
1428 	vm_address_space *addressSpace;
1429 	vm_cache_ref *cacheRef;
1430 	vm_area *target, *source;
1431 	status_t status;
1432 
1433 	if ((protection & B_KERNEL_PROTECTION) == 0)
1434 		protection |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA;
1435 
1436 	if ((source = vm_get_area(sourceID)) == NULL)
1437 		return B_BAD_VALUE;
1438 
1439 	addressSpace = vm_get_aspace_by_id(addressSpaceID);
1440 	cacheRef = source->cache_ref;
1441 
1442 	if (addressSpec == B_CLONE_ADDRESS) {
1443 		addressSpec = B_EXACT_ADDRESS;
1444 		*_address = (void *)source->base;
1445 	}
1446 
1447 	// First, create a cache on top of the source area
1448 
1449 	status = map_backing_store(addressSpace, cacheRef->cache->store, _address,
1450 		source->cache_offset, source->size, addressSpec, source->wiring, protection,
1451 		protection & (B_KERNEL_WRITE_AREA | B_WRITE_AREA) ? REGION_PRIVATE_MAP : REGION_NO_PRIVATE_MAP,
1452 		&target, name);
1453 
1454 	if (status < B_OK)
1455 		goto err;
1456 
1457 	// If the source area is writable, we need to move it one layer up as well
1458 
1459 	if ((source->protection & (B_KERNEL_WRITE_AREA | B_WRITE_AREA)) != 0)
1460 		vm_copy_on_write_area(source);
1461 
1462 	// we want to return the ID of the newly created area
1463 	status = target->id;
1464 
1465 err:
1466 	vm_put_aspace(addressSpace);
1467 	vm_put_area(source);
1468 
1469 	return status;
1470 }
1471 
1472 
1473 static int32
1474 count_writable_areas(vm_cache_ref *ref, vm_area *ignoreArea)
1475 {
1476 	struct vm_area *area = ref->areas;
1477 	uint32 count = 0;
1478 
1479 	for (; area != NULL; area = area->cache_next) {
1480 		if (area != ignoreArea
1481 			&& (area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0)
1482 			count++;
1483 	}
1484 
1485 	return count;
1486 }
1487 
1488 
1489 static status_t
1490 vm_set_area_protection(aspace_id aspaceID, area_id areaID, uint32 newProtection)
1491 {
1492 	vm_cache_ref *cacheRef;
1493 	vm_cache *cache;
1494 	vm_area *area;
1495 	status_t status = B_OK;
1496 
1497 	TRACE(("vm_set_area_protection(aspace = %#lx, area = %#lx, protection = %#lx)\n",
1498 		aspaceID, areaID, newProtection));
1499 
1500 	if (!arch_vm_supports_protection(newProtection))
1501 		return B_NOT_SUPPORTED;
1502 
1503 	area = vm_get_area(areaID);
1504 	if (area == NULL)
1505 		return B_BAD_VALUE;
1506 
1507 	if (aspaceID != vm_get_kernel_aspace_id() && area->aspace->id != aspaceID) {
1508 		// unless you're the kernel, you are only allowed to set
1509 		// the protection of your own areas
1510 		vm_put_area(area);
1511 		return B_NOT_ALLOWED;
1512 	}
1513 
1514 	cacheRef = area->cache_ref;
1515 	cache = cacheRef->cache;
1516 
1517 	mutex_lock(&cacheRef->lock);
1518 
1519 	if ((area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0
1520 		&& (newProtection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) == 0) {
1521 		// change from read/write to read-only
1522 
1523 		if (cache->source != NULL && cache->temporary) {
1524 			if (count_writable_areas(cacheRef, area) == 0) {
1525 				// Since this cache now lives from the pages in its source cache,
1526 				// we can change the cache's commitment to take only those pages
1527 				// into account that really are in this cache.
1528 
1529 				// count existing pages in this cache
1530 				struct vm_page *page = cache->page_list;
1531 				uint32 count = 0;
1532 
1533 				for (; page != NULL; page = page->cache_next) {
1534 					count++;
1535 				}
1536 
1537 				status = cache->store->ops->commit(cache->store, count * B_PAGE_SIZE);
1538 
1539 				// ToDo: we may be able to join with our source cache, if count == 0
1540 			}
1541 		}
1542 	} else if ((area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) == 0
1543 		&& (newProtection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0) {
1544 		// change from read-only to read/write
1545 
1546 		// ToDo: if this is a shared cache, insert new cache (we only know about other
1547 		//	areas in this cache yet, though, not about child areas)
1548 		//	-> use this call with care, it might currently have unwanted consequences
1549 		//	   because of this. It should always be safe though, if there are no other
1550 		//	   (child) areas referencing this area's cache (you just might not know).
1551 		if (count_writable_areas(cacheRef, area) == 0
1552 			&& (cacheRef->areas != area || area->cache_next)) {
1553 			// ToDo: child areas are not tested for yet
1554 			dprintf("set_area_protection(): warning, would need to insert a new cache_ref (not yet implemented)!\n");
1555 			status = B_NOT_ALLOWED;
1556 		} else
1557 			dprintf("set_area_protection() may not work correctly yet in this direction!\n");
1558 
1559 		if (status == B_OK && cache->source != NULL && cache->temporary) {
1560 			// the cache's commitment must contain all possible pages
1561 			status = cache->store->ops->commit(cache->store, cache->virtual_size);
1562 		}
1563 	} else {
1564 		// we don't have anything special to do in all other cases
1565 	}
1566 
1567 	if (status == B_OK && area->protection != newProtection) {
1568 		// remap existing pages in this cache
1569 		struct vm_translation_map *map = &area->aspace->translation_map;
1570 
1571 		map->ops->lock(map);
1572 		map->ops->protect(map, area->base, area->base + area->size, newProtection);
1573 		map->ops->unlock(map);
1574 
1575 		area->protection = newProtection;
1576 	}
1577 
1578 	mutex_unlock(&cacheRef->lock);
1579 	vm_put_area(area);
1580 
1581 	return status;
1582 }
1583 
1584 
1585 status_t
1586 vm_get_page_mapping(aspace_id aid, addr_t vaddr, addr_t *paddr)
1587 {
1588 	vm_address_space *aspace;
1589 	uint32 null_flags;
1590 	status_t err;
1591 
1592 	aspace = vm_get_aspace_by_id(aid);
1593 	if (aspace == NULL)
1594 		return B_BAD_TEAM_ID;
1595 
1596 	err = aspace->translation_map.ops->query(&aspace->translation_map,
1597 		vaddr, paddr, &null_flags);
1598 
1599 	vm_put_aspace(aspace);
1600 	return err;
1601 }
1602 
1603 
1604 static int
1605 display_mem(int argc, char **argv)
1606 {
1607 	int item_size;
1608 	int display_width;
1609 	int num = 1;
1610 	addr_t address;
1611 	int i;
1612 	int j;
1613 
1614 	if (argc < 2) {
1615 		dprintf("usage: dw/ds/db <address> [num]\n"
1616 			"\tdw - 4 bytes\n"
1617 			"\tds - 2 bytes\n"
1618 			"\tdb - 1 byte\n");
1619 		return 0;
1620 	}
1621 
1622 	address = strtoul(argv[1], NULL, 0);
1623 
1624 	if (argc >= 3) {
1625 		num = -1;
1626 		num = atoi(argv[2]);
1627 	}
1628 
1629 	// build the format string
1630 	if (strcmp(argv[0], "db") == 0) {
1631 		item_size = 1;
1632 		display_width = 16;
1633 	} else if (strcmp(argv[0], "ds") == 0) {
1634 		item_size = 2;
1635 		display_width = 8;
1636 	} else if (strcmp(argv[0], "dw") == 0) {
1637 		item_size = 4;
1638 		display_width = 4;
1639 	} else {
1640 		dprintf("display_mem called in an invalid way!\n");
1641 		return 0;
1642 	}
1643 
1644 	dprintf("[0x%lx] '", address);
1645 	for (j = 0; j < min_c(display_width, num) * item_size; j++) {
1646 		char c = *((char *)address + j);
1647 		if (!isalnum(c)) {
1648 			c = '.';
1649 		}
1650 		dprintf("%c", c);
1651 	}
1652 	dprintf("'");
1653 	for (i = 0; i < num; i++) {
1654 		if ((i % display_width) == 0 && i != 0) {
1655 			dprintf("\n[0x%lx] '", address + i * item_size);
1656 			for (j = 0; j < min_c(display_width, (num-i)) * item_size; j++) {
1657 				char c = *((char *)address + i * item_size + j);
1658 				if (!isalnum(c)) {
1659 					c = '.';
1660 				}
1661 				dprintf("%c", c);
1662 			}
1663 			dprintf("'");
1664 		}
1665 
1666 		switch (item_size) {
1667 			case 1:
1668 				dprintf(" 0x%02x", *((uint8 *)address + i));
1669 				break;
1670 			case 2:
1671 				dprintf(" 0x%04x", *((uint16 *)address + i));
1672 				break;
1673 			case 4:
1674 				dprintf(" 0x%08lx", *((uint32 *)address + i));
1675 				break;
1676 			default:
1677 				dprintf("huh?\n");
1678 		}
1679 	}
1680 	dprintf("\n");
1681 	return 0;
1682 }
1683 
1684 
1685 static int
1686 dump_cache_ref(int argc, char **argv)
1687 {
1688 	addr_t address;
1689 	vm_area *area;
1690 	vm_cache_ref *cache_ref;
1691 
1692 	if (argc < 2) {
1693 		dprintf("cache_ref: not enough arguments\n");
1694 		return 0;
1695 	}
1696 	if (strlen(argv[1]) < 2 || argv[1][0] != '0' || argv[1][1] != 'x') {
1697 		dprintf("cache_ref: invalid argument, pass address\n");
1698 		return 0;
1699 	}
1700 
1701 	address = atoul(argv[1]);
1702 	cache_ref = (vm_cache_ref *)address;
1703 
1704 	dprintf("cache_ref at %p:\n", cache_ref);
1705 	dprintf("cache: %p\n", cache_ref->cache);
1706 	dprintf("lock.holder: %ld\n", cache_ref->lock.holder);
1707 	dprintf("lock.sem: 0x%lx\n", cache_ref->lock.sem);
1708 	dprintf("areas:\n");
1709 	for (area = cache_ref->areas; area != NULL; area = area->cache_next) {
1710 		dprintf(" area 0x%lx: ", area->id);
1711 		dprintf("base_addr = 0x%lx ", area->base);
1712 		dprintf("size = 0x%lx ", area->size);
1713 		dprintf("name = '%s' ", area->name);
1714 		dprintf("protection = 0x%lx\n", area->protection);
1715 	}
1716 	dprintf("ref_count: %ld\n", cache_ref->ref_count);
1717 	return 0;
1718 }
1719 
1720 
1721 static const char *
1722 page_state_to_text(int state)
1723 {
1724 	switch(state) {
1725 		case PAGE_STATE_ACTIVE:
1726 			return "active";
1727 		case PAGE_STATE_INACTIVE:
1728 			return "inactive";
1729 		case PAGE_STATE_BUSY:
1730 			return "busy";
1731 		case PAGE_STATE_MODIFIED:
1732 			return "modified";
1733 		case PAGE_STATE_FREE:
1734 			return "free";
1735 		case PAGE_STATE_CLEAR:
1736 			return "clear";
1737 		case PAGE_STATE_WIRED:
1738 			return "wired";
1739 		case PAGE_STATE_UNUSED:
1740 			return "unused";
1741 		default:
1742 			return "unknown";
1743 	}
1744 }
1745 
1746 
1747 static int
1748 dump_cache(int argc, char **argv)
1749 {
1750 	addr_t address;
1751 	vm_cache *cache;
1752 	vm_page *page;
1753 
1754 	if (argc < 2) {
1755 		dprintf("cache: not enough arguments\n");
1756 		return 0;
1757 	}
1758 	if (strlen(argv[1]) < 2 || argv[1][0] != '0' || argv[1][1] != 'x') {
1759 		dprintf("cache: invalid argument, pass address\n");
1760 		return 0;
1761 	}
1762 
1763 	address = atoul(argv[1]);
1764 	cache = (vm_cache *)address;
1765 
1766 	dprintf("cache at %p:\n", cache);
1767 	dprintf("cache_ref: %p\n", cache->ref);
1768 	dprintf("source: %p\n", cache->source);
1769 	dprintf("store: %p\n", cache->store);
1770 	// XXX 64-bit
1771 	dprintf("virtual_size: 0x%Lx\n", cache->virtual_size);
1772 	dprintf("temporary: %ld\n", cache->temporary);
1773 	dprintf("scan_skip: %ld\n", cache->scan_skip);
1774 	dprintf("page_list:\n");
1775 	for (page = cache->page_list; page != NULL; page = page->cache_next) {
1776 		// XXX offset is 64-bit
1777 		if (page->type == PAGE_TYPE_PHYSICAL) {
1778 			dprintf(" %p ppn 0x%lx offset 0x%Lx type %ld state %ld (%s) ref_count %ld\n",
1779 				page, page->ppn, page->offset, page->type, page->state,
1780 				page_state_to_text(page->state), page->ref_count);
1781 		} else if(page->type == PAGE_TYPE_DUMMY) {
1782 			dprintf(" %p DUMMY PAGE state %ld (%s)\n",
1783 				page, page->state, page_state_to_text(page->state));
1784 		} else
1785 			dprintf(" %p UNKNOWN PAGE type %ld\n", page, page->type);
1786 	}
1787 	return 0;
1788 }
1789 
1790 
1791 static void
1792 _dump_area(vm_area *area)
1793 {
1794 	dprintf("dump of area at %p:\n", area);
1795 	dprintf("name: '%s'\n", area->name);
1796 	dprintf("id: 0x%lx\n", area->id);
1797 	dprintf("base: 0x%lx\n", area->base);
1798 	dprintf("size: 0x%lx\n", area->size);
1799 	dprintf("protection: 0x%lx\n", area->protection);
1800 	dprintf("wiring: 0x%lx\n", area->wiring);
1801 	dprintf("ref_count: %ld\n", area->ref_count);
1802 	dprintf("cache_ref: %p\n", area->cache_ref);
1803 	// XXX 64-bit
1804 	dprintf("cache_offset: 0x%Lx\n", area->cache_offset);
1805 	dprintf("cache_next: %p\n", area->cache_next);
1806 	dprintf("cache_prev: %p\n", area->cache_prev);
1807 }
1808 
1809 
1810 static int
1811 dump_area(int argc, char **argv)
1812 {
1813 //	int i;
1814 	vm_area *area;
1815 
1816 	if (argc < 2) {
1817 		dprintf("area: not enough arguments\n");
1818 		return 0;
1819 	}
1820 
1821 	// if the argument looks like a hex number, treat it as such
1822 	if (strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') {
1823 		uint32 num = strtoul(argv[1], NULL, 16);
1824 		area_id id = num;
1825 
1826 		area = (vm_area *)hash_lookup(sAreaHash, &id);
1827 		if (area == NULL) {
1828 			dprintf("invalid area id\n");
1829 		} else {
1830 			_dump_area(area);
1831 		}
1832 		return 0;
1833 	} else {
1834 		// walk through the area list, looking for the arguments as a name
1835 		struct hash_iterator iter;
1836 
1837 		hash_open(sAreaHash, &iter);
1838 		while ((area = (vm_area *)hash_next(sAreaHash, &iter)) != NULL) {
1839 			if (area->name != NULL && strcmp(argv[1], area->name) == 0) {
1840 				_dump_area(area);
1841 			}
1842 		}
1843 	}
1844 	return 0;
1845 }
1846 
1847 
1848 static int
1849 dump_area_list(int argc, char **argv)
1850 {
1851 	vm_area *area;
1852 	struct hash_iterator iter;
1853 
1854 	dprintf("addr\t      id  base\t\tsize\t\tprotect\tlock\tname\n");
1855 
1856 	hash_open(sAreaHash, &iter);
1857 	while ((area = (vm_area *)hash_next(sAreaHash, &iter)) != NULL) {
1858 		dprintf("%p %5lx  %p\t%p\t%ld\t%ld\t%s\n", area, area->id, (void *)area->base,
1859 			(void *)area->size, area->protection, area->wiring, area->name);
1860 	}
1861 	hash_close(sAreaHash, &iter, false);
1862 	return 0;
1863 }
1864 
1865 
1866 status_t
1867 vm_delete_areas(struct vm_address_space *aspace)
1868 {
1869 	vm_area *area;
1870 	vm_area *next, *last = NULL;
1871 
1872 	TRACE(("vm_delete_areas: called on aspace 0x%lx\n", aspace->id));
1873 
1874 	acquire_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0, 0);
1875 
1876 	// remove all reserved areas in this address space
1877 
1878 	for (area = aspace->virtual_map.areas; area; area = next) {
1879 		next = area->aspace_next;
1880 
1881 		if (area->id == RESERVED_AREA_ID) {
1882 			// just remove it
1883 			if (last)
1884 				last->aspace_next = area->aspace_next;
1885 			else
1886 				aspace->virtual_map.areas = area->aspace_next;
1887 
1888 			free(area);
1889 			continue;
1890 		}
1891 
1892 		last = area;
1893 	}
1894 
1895 	// delete all the areas in this aspace
1896 
1897 	for (area = aspace->virtual_map.areas; area; area = next) {
1898 		next = area->aspace_next;
1899 
1900 		// decrement the ref on this area, may actually push the ref < 0, if there
1901 		// is a concurrent delete_area() on that specific area, but that's ok here
1902 		if (!_vm_put_area(area, true))
1903 			dprintf("vm_delete_areas() did not delete area %p\n", area);
1904 	}
1905 
1906 	release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0);
1907 
1908 	return B_OK;
1909 }
1910 
1911 
1912 static area_id
1913 vm_area_for(aspace_id aid, addr_t address)
1914 {
1915 	vm_address_space *addressSpace;
1916 	area_id id = B_ERROR;
1917 	vm_area *area;
1918 
1919 	addressSpace = vm_get_aspace_by_id(aid);
1920 	if (addressSpace == NULL)
1921 		return B_BAD_TEAM_ID;
1922 
1923 	acquire_sem_etc(addressSpace->virtual_map.sem, READ_COUNT, 0, 0);
1924 
1925 	area = addressSpace->virtual_map.areas;
1926 	for (; area != NULL; area = area->aspace_next) {
1927 		// ignore reserved space regions
1928 		if (area->id == RESERVED_AREA_ID)
1929 			continue;
1930 
1931 		if (address >= area->base && address < area->base + area->size) {
1932 			id = area->id;
1933 			break;
1934 		}
1935 	}
1936 
1937 	release_sem_etc(addressSpace->virtual_map.sem, READ_COUNT, 0);
1938 	vm_put_aspace(addressSpace);
1939 
1940 	return id;
1941 }
1942 
1943 
1944 static void
1945 unmap_and_free_physical_pages(vm_translation_map *map, addr_t start, addr_t end)
1946 {
1947 	// free all physical pages in the specified range
1948 
1949 	for (addr_t current = start; current < end; current += B_PAGE_SIZE) {
1950 		addr_t physicalAddress;
1951 		uint32 flags;
1952 
1953 		if (map->ops->query(map, current, &physicalAddress, &flags) == B_OK) {
1954 			vm_page *page = vm_lookup_page(current / B_PAGE_SIZE);
1955 			if (page != NULL)
1956 				vm_page_set_state(page, PAGE_STATE_FREE);
1957 		}
1958 	}
1959 
1960 	// unmap the memory
1961 	map->ops->unmap(map, start, end - 1);
1962 }
1963 
1964 
1965 void
1966 vm_free_unused_boot_loader_range(addr_t start, addr_t size)
1967 {
1968 	vm_translation_map *map = &kernel_aspace->translation_map;
1969 	addr_t end = start + size;
1970 	addr_t lastEnd = start;
1971 	vm_area *area;
1972 
1973 	TRACE(("vm_free_unused_boot_loader_range(): asked to free %p - %p\n", (void *)start, (void *)end));
1974 
1975 	// The areas are sorted in virtual address space order, so
1976 	// we just have to find the holes between them that fall
1977 	// into the area we should dispose
1978 
1979 	map->ops->lock(map);
1980 
1981 	for (area = kernel_aspace->virtual_map.areas; area; area = area->aspace_next) {
1982 		addr_t areaStart = area->base;
1983 		addr_t areaEnd = areaStart + area->size;
1984 
1985 		if (area->id == RESERVED_AREA_ID)
1986 			continue;
1987 
1988 		if (areaEnd >= end) {
1989 			// we are done, the areas are already beyond of what we have to free
1990 			lastEnd = end;
1991 			break;
1992 		}
1993 
1994 		if (areaStart > lastEnd) {
1995 			// this is something we can free
1996 			TRACE(("free boot range: get rid of %p - %p\n", (void *)lastEnd, (void *)areaStart));
1997 			unmap_and_free_physical_pages(map, lastEnd, areaStart);
1998 		}
1999 
2000 		lastEnd = areaEnd;
2001 	}
2002 
2003 	if (lastEnd < end) {
2004 		// we can also get rid of some space at the end of the area
2005 		TRACE(("free boot range: also remove %p - %p\n", (void *)lastEnd, (void *)end));
2006 		unmap_and_free_physical_pages(map, lastEnd, end);
2007 	}
2008 
2009 	map->ops->unlock(map);
2010 }
2011 
2012 
2013 static void
2014 create_preloaded_image_areas(struct preloaded_image *image)
2015 {
2016 	char name[B_OS_NAME_LENGTH];
2017 	void *address;
2018 	int32 length;
2019 
2020 	// use file name to create a good area name
2021 	char *fileName = strrchr(image->name, '/');
2022 	if (fileName == NULL)
2023 		fileName = image->name;
2024 	else
2025 		fileName++;
2026 
2027 	length = strlen(fileName);
2028 	// make sure there is enough space for the suffix
2029 	if (length > 25)
2030 		length = 25;
2031 
2032 	memcpy(name, fileName, length);
2033 	strcpy(name + length, "_text");
2034 	address = (void *)ROUNDOWN(image->text_region.start, B_PAGE_SIZE);
2035 	image->text_region.id = create_area(name, &address, B_EXACT_ADDRESS,
2036 		PAGE_ALIGN(image->text_region.size), B_ALREADY_WIRED,
2037 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
2038 
2039 	strcpy(name + length, "_data");
2040 	address = (void *)ROUNDOWN(image->data_region.start, B_PAGE_SIZE);
2041 	image->data_region.id = create_area(name, &address, B_EXACT_ADDRESS,
2042 		PAGE_ALIGN(image->data_region.size), B_ALREADY_WIRED,
2043 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
2044 }
2045 
2046 
2047 /**	Frees all previously kernel arguments areas from the kernel_args structure.
2048  *	Any boot loader resources contained in that arguments must not be accessed
2049  *	anymore past this point.
2050  */
2051 
2052 void
2053 vm_free_kernel_args(kernel_args *args)
2054 {
2055 	uint32 i;
2056 
2057 	TRACE(("vm_free_kernel_args()\n"));
2058 
2059 	for (i = 0; i < args->num_kernel_args_ranges; i++) {
2060 		area_id area = area_for((void *)args->kernel_args_range[i].start);
2061 		if (area >= B_OK)
2062 			delete_area(area);
2063 	}
2064 }
2065 
2066 
2067 static void
2068 allocate_kernel_args(kernel_args *args)
2069 {
2070 	uint32 i;
2071 
2072 	TRACE(("allocate_kernel_args()\n"));
2073 
2074 	for (i = 0; i < args->num_kernel_args_ranges; i++) {
2075 		void *address = (void *)args->kernel_args_range[i].start;
2076 
2077 		create_area("_kernel args_", &address, B_EXACT_ADDRESS, args->kernel_args_range[i].size,
2078 			B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
2079 	}
2080 }
2081 
2082 
2083 static void
2084 unreserve_boot_loader_ranges(kernel_args *args)
2085 {
2086 	uint32 i;
2087 
2088 	TRACE(("unreserve_boot_loader_ranges()\n"));
2089 
2090 	for (i = 0; i < args->num_virtual_allocated_ranges; i++) {
2091 		vm_unreserve_address_range(vm_get_kernel_aspace_id(),
2092 			(void *)args->virtual_allocated_range[i].start,
2093 			args->virtual_allocated_range[i].size);
2094 	}
2095 }
2096 
2097 
2098 static void
2099 reserve_boot_loader_ranges(kernel_args *args)
2100 {
2101 	uint32 i;
2102 
2103 	TRACE(("reserve_boot_loader_ranges()\n"));
2104 
2105 	for (i = 0; i < args->num_virtual_allocated_ranges; i++) {
2106 		void *address = (void *)args->virtual_allocated_range[i].start;
2107 		status_t status = vm_reserve_address_range(vm_get_kernel_aspace_id(), &address,
2108 			B_EXACT_ADDRESS, args->virtual_allocated_range[i].size, 0);
2109 		if (status < B_OK)
2110 			panic("could not reserve boot loader ranges\n");
2111 	}
2112 }
2113 
2114 
2115 status_t
2116 vm_init(kernel_args *args)
2117 {
2118 	struct preloaded_image *image;
2119 	addr_t heap_base;
2120 	void *address;
2121 	status_t err = 0;
2122 	uint32 i;
2123 
2124 	TRACE(("vm_init: entry\n"));
2125 	err = arch_vm_translation_map_init(args);
2126 	err = arch_vm_init(args);
2127 
2128 	// initialize some globals
2129 	sNextAreaID = 1;
2130 	sAreaHashLock = -1;
2131 
2132 	// map in the new heap and initialize it
2133 	heap_base = vm_alloc_from_kernel_args(args, HEAP_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
2134 	TRACE(("heap at 0x%lx\n", heap_base));
2135 	heap_init(heap_base);
2136 
2137 	// initialize the free page list and physical page mapper
2138 	vm_page_init(args);
2139 	sAvailableMemory = vm_page_num_pages() * B_PAGE_SIZE;
2140 
2141 	// initialize the hash table that stores the pages mapped to caches
2142 	vm_cache_init(args);
2143 
2144 	{
2145 		vm_area *area;
2146 		sAreaHash = hash_init(REGION_HASH_TABLE_SIZE, (addr_t)&area->hash_next - (addr_t)area,
2147 			&area_compare, &area_hash);
2148 		if (sAreaHash == NULL)
2149 			panic("vm_init: error creating aspace hash table\n");
2150 	}
2151 
2152 	vm_aspace_init();
2153 	reserve_boot_loader_ranges(args);
2154 
2155 	// do any further initialization that the architecture dependant layers may need now
2156 	arch_vm_translation_map_init_post_area(args);
2157 	arch_vm_init_post_area(args);
2158 	vm_page_init_post_area(args);
2159 
2160 	// allocate areas to represent stuff that already exists
2161 
2162 	address = (void *)ROUNDOWN(heap_base, B_PAGE_SIZE);
2163 	create_area("kernel heap", &address, B_EXACT_ADDRESS, HEAP_SIZE,
2164 		B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
2165 
2166 	allocate_kernel_args(args);
2167 
2168 	args->kernel_image.name = "kernel";
2169 		// the lazy boot loader currently doesn't set the kernel's name...
2170 	create_preloaded_image_areas(&args->kernel_image);
2171 
2172 	// allocate areas for preloaded images
2173 	for (image = args->preloaded_images; image != NULL; image = image->next) {
2174 		create_preloaded_image_areas(image);
2175 	}
2176 
2177 	// allocate kernel stacks
2178 	for (i = 0; i < args->num_cpus; i++) {
2179 		char name[64];
2180 
2181 		sprintf(name, "idle thread %lu kstack", i + 1);
2182 		address = (void *)args->cpu_kstack[i].start;
2183 		create_area(name, &address, B_EXACT_ADDRESS, args->cpu_kstack[i].size,
2184 			B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
2185 	}
2186 	{
2187 		void *null;
2188 		vm_map_physical_memory(vm_get_kernel_aspace_id(), "bootdir", &null, B_ANY_KERNEL_ADDRESS,
2189 			args->bootdir_addr.size, B_KERNEL_READ_AREA, args->bootdir_addr.start);
2190 	}
2191 
2192 	// add some debugger commands
2193 	add_debugger_command("areas", &dump_area_list, "Dump a list of all areas");
2194 	add_debugger_command("area", &dump_area, "Dump info about a particular area");
2195 	add_debugger_command("cache_ref", &dump_cache_ref, "Dump cache_ref data structure");
2196 	add_debugger_command("cache", &dump_cache, "Dump cache_ref data structure");
2197 //	add_debugger_command("dl", &display_mem, "dump memory long words (64-bit)");
2198 	add_debugger_command("dw", &display_mem, "dump memory words (32-bit)");
2199 	add_debugger_command("ds", &display_mem, "dump memory shorts (16-bit)");
2200 	add_debugger_command("db", &display_mem, "dump memory bytes (8-bit)");
2201 
2202 	TRACE(("vm_init: exit\n"));
2203 
2204 	return err;
2205 }
2206 
2207 
2208 status_t
2209 vm_init_post_sem(kernel_args *args)
2210 {
2211 	vm_area *area;
2212 
2213 	// This frees all unused boot loader resources and makes its space available again
2214 	arch_vm_init_end(args);
2215 	unreserve_boot_loader_ranges(args);
2216 
2217 	// fill in all of the semaphores that were not allocated before
2218 	// since we're still single threaded and only the kernel address space exists,
2219 	// it isn't that hard to find all of the ones we need to create
2220 
2221 	benaphore_init(&sAvailableMemoryLock, "available memory lock");
2222 	arch_vm_translation_map_init_post_sem(args);
2223 	vm_aspace_init_post_sem();
2224 
2225 	for (area = kernel_aspace->virtual_map.areas; area; area = area->aspace_next) {
2226 		if (area->id == RESERVED_AREA_ID)
2227 			continue;
2228 
2229 		if (area->cache_ref->lock.sem < 0)
2230 			mutex_init(&area->cache_ref->lock, "cache_ref_mutex");
2231 	}
2232 
2233 	sAreaHashLock = create_sem(WRITE_COUNT, "area hash");
2234 
2235 	return heap_init_post_sem(args);
2236 }
2237 
2238 
2239 status_t
2240 vm_init_post_thread(kernel_args *args)
2241 {
2242 	vm_page_init_post_thread(args);
2243 	vm_daemon_init();
2244 	vm_low_memory_init();
2245 
2246 	return heap_init_post_thread(args);
2247 }
2248 
2249 
2250 void
2251 permit_page_faults(void)
2252 {
2253 	struct thread *thread = thread_get_current_thread();
2254 	if (thread != NULL)
2255 		atomic_add(&thread->page_faults_allowed, 1);
2256 }
2257 
2258 
2259 void
2260 forbid_page_faults(void)
2261 {
2262 	struct thread *thread = thread_get_current_thread();
2263 	if (thread != NULL)
2264 		atomic_add(&thread->page_faults_allowed, -1);
2265 }
2266 
2267 
2268 status_t
2269 vm_page_fault(addr_t address, addr_t fault_address, bool is_write, bool is_user, addr_t *newip)
2270 {
2271 	int err;
2272 
2273 	FTRACE(("vm_page_fault: page fault at 0x%lx, ip 0x%lx\n", address, fault_address));
2274 
2275 	*newip = 0;
2276 
2277 	err = vm_soft_fault(address, is_write, is_user);
2278 	if (err < 0) {
2279 		dprintf("vm_page_fault: vm_soft_fault returned error %d on fault at 0x%lx, ip 0x%lx, write %d, user %d, thread 0x%lx\n",
2280 			err, address, fault_address, is_write, is_user, thread_get_current_thread_id());
2281 		if (!is_user) {
2282 			struct thread *t = thread_get_current_thread();
2283 			if (t && t->fault_handler != 0) {
2284 				// this will cause the arch dependant page fault handler to
2285 				// modify the IP on the interrupt frame or whatever to return
2286 				// to this address
2287 				*newip = t->fault_handler;
2288 			} else {
2289 				// unhandled page fault in the kernel
2290 				panic("vm_page_fault: unhandled page fault in kernel space at 0x%lx, ip 0x%lx\n",
2291 					address, fault_address);
2292 			}
2293 		} else {
2294 #if 1
2295 			// ToDo: remove me once we have proper userland debugging support (and tools)
2296 			vm_address_space *aspace = vm_get_current_user_aspace();
2297 			vm_virtual_map *map = &aspace->virtual_map;
2298 			vm_area *area;
2299 
2300 			acquire_sem_etc(map->sem, READ_COUNT, 0, 0);
2301 			area = vm_virtual_map_lookup(map, fault_address);
2302 
2303 			dprintf("vm_page_fault: killing team 0x%lx, ip %#lx (\"%s\" +%#lx)\n",
2304 				thread_get_current_thread()->team->id, fault_address,
2305 				area ? area->name : "???", fault_address - (area ? area->base : 0x0));
2306 
2307 // We can print a stack trace of the userland thread here. Since we're accessing
2308 // user memory freely and unchecked, this is not enabled by default.
2309 #if 0
2310 			if (area) {
2311 				struct stack_frame {
2312 					#ifdef __INTEL__
2313 						struct stack_frame*	previous;
2314 						void*				return_address;
2315 					#else
2316 						// ...
2317 					#endif
2318 				};
2319 				struct iframe *iframe = i386_get_user_iframe();
2320 				struct stack_frame *frame = (struct stack_frame *)iframe->ebp;
2321 
2322 				dprintf("stack trace:\n");
2323 				for (; frame; frame = frame->previous) {
2324 					dprintf("  0x%p", frame->return_address);
2325 					area = vm_virtual_map_lookup(map,
2326 						(addr_t)frame->return_address);
2327 					if (area) {
2328 						dprintf(" (%s + %#lx)", area->name,
2329 							(addr_t)frame->return_address - area->base);
2330 					}
2331 					dprintf("\n");
2332 				}
2333 			}
2334 #endif	// 0 (stack trace)
2335 
2336 			release_sem_etc(map->sem, READ_COUNT, 0);
2337 			vm_put_aspace(aspace);
2338 #endif
2339 			if (user_debug_exception_occurred(B_SEGMENT_VIOLATION, SIGSEGV))
2340 				send_signal(team_get_current_team_id(), SIGSEGV);
2341 		}
2342 	}
2343 
2344 	return B_HANDLED_INTERRUPT;
2345 }
2346 
2347 
2348 static status_t
2349 vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser)
2350 {
2351 	vm_address_space *aspace;
2352 	vm_virtual_map *map;
2353 	vm_area *area;
2354 	vm_cache_ref *cache_ref;
2355 	vm_cache_ref *last_cache_ref;
2356 	vm_cache_ref *top_cache_ref;
2357 	off_t cache_offset;
2358 	vm_page dummy_page;
2359 	vm_page *page = NULL;
2360 	addr_t address;
2361 	int change_count;
2362 	int err;
2363 
2364 	FTRACE(("vm_soft_fault: thid 0x%lx address 0x%lx, isWrite %d, isUser %d\n",
2365 		thread_get_current_thread_id(), originalAddress, isWrite, isUser));
2366 
2367 	address = ROUNDOWN(originalAddress, B_PAGE_SIZE);
2368 
2369 	if (IS_KERNEL_ADDRESS(address)) {
2370 		aspace = vm_get_kernel_aspace();
2371 	} else if (IS_USER_ADDRESS(address)) {
2372 		aspace = vm_get_current_user_aspace();
2373 		if (aspace == NULL) {
2374 			if (isUser == false) {
2375 				dprintf("vm_soft_fault: kernel thread accessing invalid user memory!\n");
2376 				return B_BAD_ADDRESS;
2377 			} else {
2378 				// XXX weird state.
2379 				panic("vm_soft_fault: non kernel thread accessing user memory that doesn't exist!\n");
2380 			}
2381 		}
2382 	} else {
2383 		// the hit was probably in the 64k DMZ between kernel and user space
2384 		// this keeps a user space thread from passing a buffer that crosses into kernel space
2385 		return B_BAD_ADDRESS;
2386 	}
2387 	map = &aspace->virtual_map;
2388 	atomic_add(&aspace->fault_count, 1);
2389 
2390 	// Get the area the fault was in
2391 
2392 	acquire_sem_etc(map->sem, READ_COUNT, 0, 0);
2393 	area = vm_virtual_map_lookup(map, address);
2394 	if (area == NULL) {
2395 		release_sem_etc(map->sem, READ_COUNT, 0);
2396 		vm_put_aspace(aspace);
2397 		dprintf("vm_soft_fault: va 0x%lx not covered by area in address space\n", originalAddress);
2398 		return B_BAD_ADDRESS;
2399 	}
2400 
2401 	// check permissions
2402 	if (isUser && (area->protection & B_USER_PROTECTION) == 0) {
2403 		release_sem_etc(map->sem, READ_COUNT, 0);
2404 		vm_put_aspace(aspace);
2405 		dprintf("user access on kernel area 0x%lx at %p\n", area->id, (void *)originalAddress);
2406 		return B_PERMISSION_DENIED;
2407 	}
2408 	if (isWrite && (area->protection & (B_WRITE_AREA | (isUser ? 0 : B_KERNEL_WRITE_AREA))) == 0) {
2409 		release_sem_etc(map->sem, READ_COUNT, 0);
2410 		vm_put_aspace(aspace);
2411 		dprintf("write access attempted on read-only area 0x%lx at %p\n", area->id, (void *)originalAddress);
2412 		return B_PERMISSION_DENIED;
2413 	}
2414 
2415 	// We have the area, it was a valid access, so let's try to resolve the page fault now.
2416 	// At first, the top most cache from the area is investigated
2417 
2418 	top_cache_ref = area->cache_ref;
2419 	cache_offset = address - area->base + area->cache_offset;
2420 	vm_cache_acquire_ref(top_cache_ref, true);
2421 	change_count = map->change_count;
2422 	release_sem_etc(map->sem, READ_COUNT, 0);
2423 
2424 	// See if this cache has a fault handler - this will do all the work for us
2425 	if (top_cache_ref->cache->store->ops->fault != NULL) {
2426 		// Note, since the page fault is resolved with interrupts enabled, the
2427 		// fault handler could be called more than once for the same reason -
2428 		// the store must take this into account
2429 		status_t status = (*top_cache_ref->cache->store->ops->fault)(top_cache_ref->cache->store, aspace, cache_offset);
2430 		if (status != B_BAD_HANDLER) {
2431 			vm_cache_release_ref(top_cache_ref);
2432 			vm_put_aspace(aspace);
2433 			return status;
2434 		}
2435 	}
2436 
2437 	// The top most cache has no fault handler, so let's see if the cache or its sources
2438 	// already have the page we're searching for (we're going from top to bottom)
2439 
2440 	dummy_page.state = PAGE_STATE_INACTIVE;
2441 	dummy_page.type = PAGE_TYPE_DUMMY;
2442 
2443 	last_cache_ref = top_cache_ref;
2444 	for (cache_ref = top_cache_ref; cache_ref; cache_ref = (cache_ref->cache->source) ? cache_ref->cache->source->ref : NULL) {
2445 		mutex_lock(&cache_ref->lock);
2446 
2447 		for (;;) {
2448 			page = vm_cache_lookup_page(cache_ref, cache_offset);
2449 			if (page != NULL && page->state != PAGE_STATE_BUSY) {
2450 				vm_page_set_state(page, PAGE_STATE_BUSY);
2451 				mutex_unlock(&cache_ref->lock);
2452 				break;
2453 			}
2454 
2455 			if (page == NULL)
2456 				break;
2457 
2458 			// page must be busy
2459 			// ToDo: don't wait forever!
2460 			mutex_unlock(&cache_ref->lock);
2461 			snooze(20000);
2462 			mutex_lock(&cache_ref->lock);
2463 		}
2464 
2465 		if (page != NULL)
2466 			break;
2467 
2468 		// The current cache does not contain the page we're looking for
2469 
2470 		// If we're at the top most cache, insert the dummy page here to keep other threads
2471 		// from faulting on the same address and chasing us up the cache chain
2472 		if (cache_ref == top_cache_ref) {
2473 			dummy_page.state = PAGE_STATE_BUSY;
2474 			vm_cache_insert_page(cache_ref, &dummy_page, cache_offset);
2475 		}
2476 
2477 		// see if the vm_store has it
2478 		if (cache_ref->cache->store->ops->has_page != NULL
2479 			&& cache_ref->cache->store->ops->has_page(cache_ref->cache->store, cache_offset)) {
2480 			size_t bytesRead;
2481 			iovec vec;
2482 
2483 			vec.iov_len = bytesRead = B_PAGE_SIZE;
2484 
2485 			mutex_unlock(&cache_ref->lock);
2486 
2487 			page = vm_page_allocate_page(PAGE_STATE_FREE);
2488 			aspace->translation_map.ops->get_physical_page(page->ppn * B_PAGE_SIZE, (addr_t *)&vec.iov_base, PHYSICAL_PAGE_CAN_WAIT);
2489 			// ToDo: handle errors here
2490 			err = cache_ref->cache->store->ops->read(cache_ref->cache->store, cache_offset, &vec, 1, &bytesRead);
2491 			aspace->translation_map.ops->put_physical_page((addr_t)vec.iov_base);
2492 
2493 			mutex_lock(&cache_ref->lock);
2494 
2495 			if (cache_ref == top_cache_ref) {
2496 				vm_cache_remove_page(cache_ref, &dummy_page);
2497 				dummy_page.state = PAGE_STATE_INACTIVE;
2498 			}
2499 			vm_cache_insert_page(cache_ref, page, cache_offset);
2500 			mutex_unlock(&cache_ref->lock);
2501 			break;
2502 		}
2503 		mutex_unlock(&cache_ref->lock);
2504 		last_cache_ref = cache_ref;
2505 	}
2506 
2507 	if (!cache_ref) {
2508 		// We rolled off the end of the cache chain, so we need to decide which
2509 		// cache will get the new page we're about to create.
2510 
2511 		cache_ref = isWrite ? top_cache_ref : last_cache_ref;
2512 			// Read-only pages come in the deepest cache - only the
2513 			// top most cache may have direct write access.
2514 	}
2515 
2516 	if (page == NULL) {
2517 		// we still haven't found a page, so we allocate a clean one
2518 		page = vm_page_allocate_page(PAGE_STATE_CLEAR);
2519 		FTRACE(("vm_soft_fault: just allocated page 0x%lx\n", page->ppn));
2520 
2521 		// Insert the new page into our cache, and replace it with the dummy page if necessary
2522 
2523 		mutex_lock(&cache_ref->lock);
2524 
2525 		// if we inserted a dummy page into this cache, we have to remove it now
2526 		if (dummy_page.state == PAGE_STATE_BUSY && dummy_page.cache == cache_ref->cache) {
2527 			vm_cache_remove_page(cache_ref, &dummy_page);
2528 			dummy_page.state = PAGE_STATE_INACTIVE;
2529 		}
2530 
2531 		vm_cache_insert_page(cache_ref, page, cache_offset);
2532 		mutex_unlock(&cache_ref->lock);
2533 
2534 		if (dummy_page.state == PAGE_STATE_BUSY) {
2535 			// we had inserted the dummy cache in another cache, so let's remove it from there
2536 			vm_cache_ref *temp_cache = dummy_page.cache->ref;
2537 			mutex_lock(&temp_cache->lock);
2538 			vm_cache_remove_page(temp_cache, &dummy_page);
2539 			mutex_unlock(&temp_cache->lock);
2540 			dummy_page.state = PAGE_STATE_INACTIVE;
2541 		}
2542 	}
2543 
2544 	// We now have the page and a cache it belongs to - we now need to make
2545 	// sure that the area's cache can access it, too, and sees the correct data
2546 
2547 	if (page->cache != top_cache_ref->cache && isWrite) {
2548 		// now we have a page that has the data we want, but in the wrong cache object
2549 		// so we need to copy it and stick it into the top cache
2550 		vm_page *src_page = page;
2551 		void *src, *dest;
2552 
2553 		FTRACE(("get new page, copy it, and put it into the topmost cache\n"));
2554 		page = vm_page_allocate_page(PAGE_STATE_FREE);
2555 
2556 		// try to get a mapping for the src and dest page so we can copy it
2557 		for (;;) {
2558 			(*aspace->translation_map.ops->get_physical_page)(src_page->ppn * B_PAGE_SIZE, (addr_t *)&src, PHYSICAL_PAGE_CAN_WAIT);
2559 			err = (*aspace->translation_map.ops->get_physical_page)(page->ppn * B_PAGE_SIZE, (addr_t *)&dest, PHYSICAL_PAGE_NO_WAIT);
2560 			if (err == B_NO_ERROR)
2561 				break;
2562 
2563 			// it couldn't map the second one, so sleep and retry
2564 			// keeps an extremely rare deadlock from occuring
2565 			(*aspace->translation_map.ops->put_physical_page)((addr_t)src);
2566 			snooze(5000);
2567 		}
2568 
2569 		memcpy(dest, src, B_PAGE_SIZE);
2570 		(*aspace->translation_map.ops->put_physical_page)((addr_t)src);
2571 		(*aspace->translation_map.ops->put_physical_page)((addr_t)dest);
2572 
2573 		vm_page_set_state(src_page, PAGE_STATE_ACTIVE);
2574 
2575 		mutex_lock(&top_cache_ref->lock);
2576 
2577 		// Insert the new page into our cache, and replace it with the dummy page if necessary
2578 
2579 		// if we inserted a dummy page into this cache, we have to remove it now
2580 		if (dummy_page.state == PAGE_STATE_BUSY && dummy_page.cache == top_cache_ref->cache) {
2581 			vm_cache_remove_page(top_cache_ref, &dummy_page);
2582 			dummy_page.state = PAGE_STATE_INACTIVE;
2583 		}
2584 
2585 		vm_cache_insert_page(top_cache_ref, page, cache_offset);
2586 		mutex_unlock(&top_cache_ref->lock);
2587 
2588 		if (dummy_page.state == PAGE_STATE_BUSY) {
2589 			// we had inserted the dummy cache in another cache, so let's remove it from there
2590 			vm_cache_ref *temp_cache = dummy_page.cache->ref;
2591 			mutex_lock(&temp_cache->lock);
2592 			vm_cache_remove_page(temp_cache, &dummy_page);
2593 			mutex_unlock(&temp_cache->lock);
2594 			dummy_page.state = PAGE_STATE_INACTIVE;
2595 		}
2596 	}
2597 
2598 	err = B_OK;
2599 	acquire_sem_etc(map->sem, READ_COUNT, 0, 0);
2600 	if (change_count != map->change_count) {
2601 		// something may have changed, see if the address is still valid
2602 		area = vm_virtual_map_lookup(map, address);
2603 		if (area == NULL
2604 			|| area->cache_ref != top_cache_ref
2605 			|| (address - area->base + area->cache_offset) != cache_offset) {
2606 			dprintf("vm_soft_fault: address space layout changed effecting ongoing soft fault\n");
2607 			err = B_BAD_ADDRESS;
2608 		}
2609 	}
2610 
2611 	if (err == B_OK) {
2612 		// All went fine, all there is left to do is to map the page into the address space
2613 
2614 		// If the page doesn't reside in the area's cache, we need to make sure it's
2615 		// mapped in read-only, so that we cannot overwrite someone else's data (copy-on-write)
2616 		uint32 newProtection = area->protection;
2617 		if (page->cache != top_cache_ref->cache && !isWrite)
2618 			newProtection &= ~(isUser ? B_WRITE_AREA : B_KERNEL_WRITE_AREA);
2619 
2620 		atomic_add(&page->ref_count, 1);
2621 		(*aspace->translation_map.ops->lock)(&aspace->translation_map);
2622 		(*aspace->translation_map.ops->map)(&aspace->translation_map, address,
2623 			page->ppn * B_PAGE_SIZE, newProtection);
2624 		(*aspace->translation_map.ops->unlock)(&aspace->translation_map);
2625 	}
2626 
2627 	release_sem_etc(map->sem, READ_COUNT, 0);
2628 
2629 	if (dummy_page.state == PAGE_STATE_BUSY) {
2630 		// We still have the dummy page in the cache - that happens if we didn't need
2631 		// to allocate a new page before, but could use one in another cache
2632 		vm_cache_ref *temp_cache = dummy_page.cache->ref;
2633 		mutex_lock(&temp_cache->lock);
2634 		vm_cache_remove_page(temp_cache, &dummy_page);
2635 		mutex_unlock(&temp_cache->lock);
2636 		dummy_page.state = PAGE_STATE_INACTIVE;
2637 	}
2638 
2639 	vm_page_set_state(page, PAGE_STATE_ACTIVE);
2640 
2641 	vm_cache_release_ref(top_cache_ref);
2642 	vm_put_aspace(aspace);
2643 
2644 	return err;
2645 }
2646 
2647 
2648 static vm_area *
2649 vm_virtual_map_lookup(vm_virtual_map *map, addr_t address)
2650 {
2651 	vm_area *area;
2652 
2653 	// check the areas list first
2654 	area = map->area_hint;
2655 	if (area && area->base <= address && (area->base + area->size) > address)
2656 		return area;
2657 
2658 	for (area = map->areas; area != NULL; area = area->aspace_next) {
2659 		if (area->id == RESERVED_AREA_ID)
2660 			continue;
2661 
2662 		if (area->base <= address && (area->base + area->size) > address)
2663 			break;
2664 	}
2665 
2666 	if (area)
2667 		map->area_hint = area;
2668 	return area;
2669 }
2670 
2671 
2672 status_t
2673 vm_get_physical_page(addr_t paddr, addr_t *_vaddr, int flags)
2674 {
2675 	return (*kernel_aspace->translation_map.ops->get_physical_page)(paddr, _vaddr, flags);
2676 }
2677 
2678 
2679 status_t
2680 vm_put_physical_page(addr_t vaddr)
2681 {
2682 	return (*kernel_aspace->translation_map.ops->put_physical_page)(vaddr);
2683 }
2684 
2685 
2686 void
2687 vm_unreserve_memory(size_t amount)
2688 {
2689 	benaphore_lock(&sAvailableMemoryLock);
2690 
2691 	sAvailableMemory += amount;
2692 
2693 	benaphore_unlock(&sAvailableMemoryLock);
2694 }
2695 
2696 
2697 status_t
2698 vm_try_reserve_memory(size_t amount)
2699 {
2700 	status_t status;
2701 	benaphore_lock(&sAvailableMemoryLock);
2702 
2703 	if (sAvailableMemory > amount) {
2704 		sAvailableMemory -= amount;
2705 		status = B_OK;
2706 	} else
2707 		status = B_NO_MEMORY;
2708 
2709 	benaphore_unlock(&sAvailableMemoryLock);
2710 	return status;
2711 }
2712 
2713 
2714 /**	This function enforces some protection properties:
2715  *	 - if B_WRITE_AREA is set, B_WRITE_KERNEL_AREA is set as well
2716  *	 - if only B_READ_AREA has been set, B_KERNEL_READ_AREA is also set
2717  *	 - if no protection is specified, it defaults to B_KERNEL_READ_AREA
2718  *	   and B_KERNEL_WRITE_AREA.
2719  */
2720 
2721 static void
2722 fix_protection(uint32 *protection)
2723 {
2724 	if ((*protection & B_KERNEL_PROTECTION) == 0) {
2725 		if ((*protection & B_USER_PROTECTION) == 0
2726 			|| (*protection & B_WRITE_AREA) != 0)
2727 			*protection |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA;
2728 		else
2729 			*protection |= B_KERNEL_READ_AREA;
2730 	}
2731 }
2732 
2733 
2734 //	#pragma mark -
2735 
2736 
2737 status_t
2738 user_memcpy(void *to, const void *from, size_t size)
2739 {
2740 	return arch_cpu_user_memcpy(to, from, size, &thread_get_current_thread()->fault_handler);
2741 }
2742 
2743 
2744 /**	\brief Copies at most (\a size - 1) characters from the string in \a from to
2745  *	the string in \a to, NULL-terminating the result.
2746  *
2747  *	\param to Pointer to the destination C-string.
2748  *	\param from Pointer to the source C-string.
2749  *	\param size Size in bytes of the string buffer pointed to by \a to.
2750  *
2751  *	\return strlen(\a from).
2752  */
2753 
2754 ssize_t
2755 user_strlcpy(char *to, const char *from, size_t size)
2756 {
2757 	return arch_cpu_user_strlcpy(to, from, size, &thread_get_current_thread()->fault_handler);
2758 }
2759 
2760 
2761 status_t
2762 user_memset(void *s, char c, size_t count)
2763 {
2764 	return arch_cpu_user_memset(s, c, count, &thread_get_current_thread()->fault_handler);
2765 }
2766 
2767 
2768 //	#pragma mark -
2769 
2770 
2771 long
2772 lock_memory(void *address, ulong numBytes, ulong flags)
2773 {
2774 	vm_address_space *aspace = NULL;
2775 	struct vm_translation_map *map;
2776 	addr_t base = (addr_t)address;
2777 	addr_t end = base + numBytes;
2778 	bool isUser = IS_USER_ADDRESS(address);
2779 
2780 	// ToDo: Our VM currently doesn't support locking, this function
2781 	//	will now at least make sure that the memory is paged in, but
2782 	//	that's about it.
2783 	//	Nevertheless, it must be implemented as soon as we're able to
2784 	//	swap pages out of memory.
2785 
2786 	// ToDo: this is a hack, too; the iospace area is a null region and
2787 	//	officially cannot be written to or read; ie. vm_soft_fault() will
2788 	//	fail there. Furthermore, this is x86 specific as well.
2789 	#define IOSPACE_SIZE (256 * 1024 * 1024)
2790 	if (base >= KERNEL_BASE + IOSPACE_SIZE && base + numBytes < KERNEL_BASE + 2 * IOSPACE_SIZE)
2791 		return B_OK;
2792 
2793 	if (isUser)
2794 		aspace = vm_get_current_user_aspace();
2795 	else
2796 		aspace = vm_get_kernel_aspace();
2797 	if (aspace == NULL)
2798 		return B_ERROR;
2799 
2800 	map = &aspace->translation_map;
2801 
2802 	for (; base < end; base += B_PAGE_SIZE) {
2803 		addr_t physicalAddress;
2804 		uint32 protection;
2805 		status_t status;
2806 
2807 		map->ops->lock(map);
2808 		map->ops->query(map, base, &physicalAddress, &protection);
2809 		map->ops->unlock(map);
2810 
2811 		if ((protection & PAGE_PRESENT) != 0) {
2812 			// if B_READ_DEVICE is set, the caller intents to write to the locked
2813 			// memory, so if it hasn't been mapped writable, we'll try the soft
2814 			// fault anyway
2815 			if ((flags & B_READ_DEVICE) == 0
2816 				|| (protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0)
2817 			continue;
2818 		}
2819 
2820 		status = vm_soft_fault(base, (flags & B_READ_DEVICE) != 0, isUser);
2821 		if (status != B_OK)	{
2822 			dprintf("lock_memory(address = %p, numBytes = %lu, flags = %lu) failed: %s\n",
2823 				address, numBytes, flags, strerror(status));
2824 			vm_put_aspace(aspace);
2825 			return status;
2826 		}
2827 	}
2828 
2829 	vm_put_aspace(aspace);
2830 	return B_OK;
2831 }
2832 
2833 
2834 long
2835 unlock_memory(void *buffer, ulong numBytes, ulong flags)
2836 {
2837 	return B_OK;
2838 }
2839 
2840 
2841 /** According to the BeBook, this function should always succeed.
2842  *	This is no longer the case.
2843  */
2844 
2845 long
2846 get_memory_map(const void *address, ulong numBytes, physical_entry *table, long numEntries)
2847 {
2848 	vm_address_space *addressSpace;
2849 	addr_t virtualAddress = (addr_t)address;
2850 	addr_t pageOffset = virtualAddress & (B_PAGE_SIZE - 1);
2851 	addr_t physicalAddress;
2852 	status_t status = B_OK;
2853 	int32 index = -1;
2854 	addr_t offset = 0;
2855 	uint32 flags;
2856 
2857 	TRACE(("get_memory_map(%p, %lu bytes, %ld entries)\n", address, numBytes, numEntries));
2858 
2859 	if (numEntries == 0 || numBytes == 0)
2860 		return B_BAD_VALUE;
2861 
2862 	// in which address space is the address to be found?
2863 	if (IS_USER_ADDRESS(virtualAddress))
2864 		addressSpace = vm_get_current_user_aspace();
2865 	else
2866 		addressSpace = vm_get_kernel_aspace();
2867 
2868 	if (addressSpace == NULL)
2869 		return B_ERROR;
2870 
2871 	(*addressSpace->translation_map.ops->lock)(&addressSpace->translation_map);
2872 
2873 	while (offset < numBytes) {
2874 		addr_t bytes = min_c(numBytes - offset, B_PAGE_SIZE);
2875 
2876 		status = (*addressSpace->translation_map.ops->query)(&addressSpace->translation_map,
2877 					(addr_t)address + offset, &physicalAddress, &flags);
2878 		if (status < 0)
2879 			break;
2880 
2881 		if (index < 0 && pageOffset > 0) {
2882 			physicalAddress += pageOffset;
2883 			if (bytes > B_PAGE_SIZE - pageOffset)
2884 				bytes = B_PAGE_SIZE - pageOffset;
2885 		}
2886 
2887 		// need to switch to the next physical_entry?
2888 		if (index < 0 || (addr_t)table[index].address != physicalAddress - table[index].size) {
2889 			if (++index + 1 > numEntries) {
2890 				// table to small
2891 				status = B_BUFFER_OVERFLOW;
2892 				break;
2893 			}
2894 			table[index].address = (void *)physicalAddress;
2895 			table[index].size = bytes;
2896 		} else {
2897 			// page does fit in current entry
2898 			table[index].size += bytes;
2899 		}
2900 
2901 		offset += bytes;
2902 	}
2903 	(*addressSpace->translation_map.ops->unlock)(&addressSpace->translation_map);
2904 
2905 	// close the entry list
2906 
2907 	if (status == B_OK) {
2908 		// if it's only one entry, we will silently accept the missing ending
2909 		if (numEntries == 1)
2910 			return B_OK;
2911 
2912 		if (++index + 1 > numEntries)
2913 			return B_BUFFER_OVERFLOW;
2914 
2915 		table[index].address = NULL;
2916 		table[index].size = 0;
2917 	}
2918 
2919 	return status;
2920 }
2921 
2922 
2923 area_id
2924 area_for(void *address)
2925 {
2926 	return vm_area_for(vm_get_kernel_aspace_id(), (addr_t)address);
2927 }
2928 
2929 
2930 area_id
2931 find_area(const char *name)
2932 {
2933 	struct hash_iterator iterator;
2934 	vm_area *area;
2935 	area_id id = B_NAME_NOT_FOUND;
2936 
2937 	acquire_sem_etc(sAreaHashLock, READ_COUNT, 0, 0);
2938 	hash_open(sAreaHash, &iterator);
2939 
2940 	while ((area = (vm_area *)hash_next(sAreaHash, &iterator)) != NULL) {
2941 		if (area->id == RESERVED_AREA_ID)
2942 			continue;
2943 
2944 		if (!strcmp(area->name, name)) {
2945 			id = area->id;
2946 			break;
2947 		}
2948 	}
2949 
2950 	hash_close(sAreaHash, &iterator, false);
2951 	release_sem_etc(sAreaHashLock, READ_COUNT, 0);
2952 
2953 	return id;
2954 }
2955 
2956 
2957 static void
2958 fill_area_info(struct vm_area *area, area_info *info, size_t size)
2959 {
2960 	strlcpy(info->name, area->name, B_OS_NAME_LENGTH);
2961 	info->area = area->id;
2962 	info->address = (void *)area->base;
2963 	info->size = area->size;
2964 	info->protection = area->protection & B_USER_PROTECTION;
2965 	info->lock = B_FULL_LOCK;
2966 	info->team = area->aspace->id;
2967 	info->ram_size = area->size;
2968 	info->copy_count = 0;
2969 	info->in_count = 0;
2970 	info->out_count = 0;
2971 		// ToDo: retrieve real values here!
2972 }
2973 
2974 
2975 status_t
2976 _get_area_info(area_id id, area_info *info, size_t size)
2977 {
2978 	vm_area *area;
2979 
2980 	if (size != sizeof(area_info) || info == NULL)
2981 		return B_BAD_VALUE;
2982 
2983 	area = vm_get_area(id);
2984 	if (area == NULL)
2985 		return B_BAD_VALUE;
2986 
2987 	fill_area_info(area, info, size);
2988 	vm_put_area(area);
2989 
2990 	return B_OK;
2991 }
2992 
2993 
2994 status_t
2995 _get_next_area_info(team_id team, int32 *cookie, area_info *info, size_t size)
2996 {
2997 	addr_t nextBase = *(addr_t *)cookie;
2998 	vm_address_space *addressSpace;
2999 	vm_area *area;
3000 
3001 	// we're already through the list
3002 	if (nextBase == (addr_t)-1)
3003 		return B_ENTRY_NOT_FOUND;
3004 
3005 	if (team == B_CURRENT_TEAM)
3006 		team = team_get_current_team_id();
3007 
3008 	if (!team_is_valid(team)
3009 		|| team_get_address_space(team, &addressSpace) != B_OK)
3010 		return B_BAD_VALUE;
3011 
3012 	acquire_sem_etc(addressSpace->virtual_map.sem, READ_COUNT, 0, 0);
3013 
3014 	for (area = addressSpace->virtual_map.areas; area; area = area->aspace_next) {
3015 		if (area->id == RESERVED_AREA_ID)
3016 			continue;
3017 
3018 		if (area->base > nextBase)
3019 			break;
3020 	}
3021 
3022 	// make sure this area won't go away
3023 	if (area != NULL)
3024 		area = vm_get_area(area->id);
3025 
3026 	release_sem_etc(addressSpace->virtual_map.sem, READ_COUNT, 0);
3027 	vm_put_aspace(addressSpace);
3028 
3029 	if (area == NULL) {
3030 		nextBase = (addr_t)-1;
3031 		return B_ENTRY_NOT_FOUND;
3032 	}
3033 
3034 	fill_area_info(area, info, size);
3035 	*cookie = (int32)(area->base);
3036 
3037 	vm_put_area(area);
3038 
3039 	return B_OK;
3040 }
3041 
3042 
3043 status_t
3044 set_area_protection(area_id area, uint32 newProtection)
3045 {
3046 	fix_protection(&newProtection);
3047 
3048 	return vm_set_area_protection(vm_get_kernel_aspace_id(), area, newProtection);
3049 }
3050 
3051 
3052 status_t
3053 resize_area(area_id areaID, size_t newSize)
3054 {
3055 	vm_cache_ref *cache;
3056 	vm_area *area, *current;
3057 	status_t status = B_OK;
3058 	size_t oldSize;
3059 
3060 	// is newSize a multiple of B_PAGE_SIZE?
3061 	if (newSize & (B_PAGE_SIZE - 1))
3062 		return B_BAD_VALUE;
3063 
3064 	area = vm_get_area(areaID);
3065 	if (area == NULL)
3066 		return B_BAD_VALUE;
3067 
3068 	// Resize all areas of this area's cache
3069 
3070 	cache = area->cache_ref;
3071 	oldSize = area->size;
3072 
3073 	// ToDo: we should only allow to resize anonymous memory areas!
3074 	if (!cache->cache->temporary) {
3075 		status = B_NOT_ALLOWED;
3076 		goto err1;
3077 	}
3078 
3079 	// ToDo: we must lock all address spaces here!
3080 
3081 	mutex_lock(&cache->lock);
3082 
3083 	if (oldSize < newSize) {
3084 		// We need to check if all areas of this cache can be resized
3085 
3086 		for (current = cache->areas; current; current = current->cache_next) {
3087 			if (current->aspace_next && current->aspace_next->base <= (current->base + newSize)) {
3088 				// if the area was created inside a reserved area, it can also be
3089 				// resized in that area
3090 				// ToDo: if there is free space after the reserved area, it could be used as well...
3091 				vm_area *next = current->aspace_next;
3092 				if (next->id == RESERVED_AREA_ID && next->cache_offset <= current->base
3093 					&& next->base - 1 + next->size >= current->base - 1 + newSize)
3094 					continue;
3095 
3096 				status = B_ERROR;
3097 				goto err2;
3098 			}
3099 		}
3100 	}
3101 
3102 	// Okay, looks good so far, so let's do it
3103 
3104 	for (current = cache->areas; current; current = current->cache_next) {
3105 		if (current->aspace_next && current->aspace_next->base <= (current->base + newSize)) {
3106 			vm_area *next = current->aspace_next;
3107 			if (next->id == RESERVED_AREA_ID && next->cache_offset <= current->base
3108 				&& next->base - 1 + next->size >= current->base - 1 + newSize) {
3109 				// resize reserved area
3110 				addr_t offset = current->base + newSize - next->base;
3111 				if (next->size <= offset) {
3112 					current->aspace_next = next->aspace_next;
3113 					free(next);
3114 				} else {
3115 					next->size -= offset;
3116 					next->base += offset;
3117 				}
3118 			} else {
3119 				status = B_ERROR;
3120 				break;
3121 			}
3122 		}
3123 
3124 		current->size = newSize;
3125 
3126 		// we also need to unmap all pages beyond the new size, if the area has shrinked
3127 		if (newSize < oldSize) {
3128 			vm_translation_map *map = &current->aspace->translation_map;
3129 
3130 			map->ops->lock(map);
3131 			map->ops->unmap(map, current->base + newSize, current->base + oldSize - 1);
3132 			map->ops->unlock(map);
3133 		}
3134 	}
3135 
3136 	if (status == B_OK)
3137 		status = vm_cache_resize(cache, newSize);
3138 
3139 	if (status < B_OK) {
3140 		// This shouldn't really be possible, but hey, who knows
3141 		for (current = cache->areas; current; current = current->cache_next)
3142 			current->size = oldSize;
3143 	}
3144 
3145 err2:
3146 	mutex_unlock(&cache->lock);
3147 err1:
3148 	vm_put_area(area);
3149 
3150 	// ToDo: we must honour the lock restrictions of this area
3151 	return status;
3152 }
3153 
3154 
3155 /**	Transfers the specified area to a new team. The caller must be the owner
3156  *	of the area (not yet enforced but probably should be).
3157  *	This function is currently not exported to the kernel namespace, but is
3158  *	only accessible using the _kern_transfer_area() syscall.
3159  */
3160 
3161 static status_t
3162 transfer_area(area_id id, void **_address, uint32 addressSpec, team_id target)
3163 {
3164 	vm_address_space *sourceAddressSpace, *targetAddressSpace;
3165 	vm_translation_map *map;
3166 	vm_area *area, *reserved;
3167 	void *reservedAddress;
3168 	status_t status;
3169 
3170 	area = vm_get_area(id);
3171 	if (area == NULL)
3172 		return B_BAD_VALUE;
3173 
3174 	// ToDo: check if the current team owns the area
3175 
3176 	status = team_get_address_space(target, &targetAddressSpace);
3177 	if (status != B_OK)
3178 		goto err1;
3179 
3180 	// We will first remove the area, and then reserve its former
3181 	// address range so that we can later reclaim it if the
3182 	// transfer failed.
3183 
3184 	sourceAddressSpace = area->aspace;
3185 
3186 	reserved = _vm_create_reserved_region_struct(&sourceAddressSpace->virtual_map, 0);
3187 	if (reserved == NULL) {
3188 		status = B_NO_MEMORY;
3189 		goto err2;
3190 	}
3191 
3192 	acquire_sem_etc(sourceAddressSpace->virtual_map.sem, WRITE_COUNT, 0, 0);
3193 
3194 	reservedAddress = (void *)area->base;
3195 	remove_area_from_virtual_map(sourceAddressSpace, area, true);
3196 	status = insert_area(sourceAddressSpace, &reservedAddress, B_EXACT_ADDRESS,
3197 		area->size, reserved);
3198 		// famous last words: this cannot fail :)
3199 
3200 	release_sem_etc(sourceAddressSpace->virtual_map.sem, WRITE_COUNT, 0);
3201 
3202 	if (status != B_OK)
3203 		goto err3;
3204 
3205 	// unmap the area in the source address space
3206 	map = &sourceAddressSpace->translation_map;
3207 	map->ops->lock(map);
3208 	map->ops->unmap(map, area->base, area->base + (area->size - 1));
3209 	map->ops->unlock(map);
3210 
3211 	// insert the area into the target address space
3212 
3213 	acquire_sem_etc(targetAddressSpace->virtual_map.sem, WRITE_COUNT, 0, 0);
3214 	// check to see if this aspace has entered DELETE state
3215 	if (targetAddressSpace->state == VM_ASPACE_STATE_DELETION) {
3216 		// okay, someone is trying to delete this aspace now, so we can't
3217 		// insert the area, so back out
3218 		status = B_BAD_TEAM_ID;
3219 		goto err4;
3220 	}
3221 
3222 	status = insert_area(targetAddressSpace, _address, addressSpec, area->size, area);
3223 	if (status < B_OK)
3224 		goto err4;
3225 
3226 	// The area was successfully transferred to the new team when we got here
3227 	area->aspace = targetAddressSpace;
3228 
3229 	release_sem_etc(targetAddressSpace->virtual_map.sem, WRITE_COUNT, 0);
3230 
3231 	vm_unreserve_address_range(sourceAddressSpace->id, reservedAddress, area->size);
3232 	vm_put_aspace(sourceAddressSpace);
3233 		// we keep the reference of the target address space for the
3234 		// area, so we only have to put the one from the source
3235 	vm_put_area(area);
3236 
3237 	return B_OK;
3238 
3239 err4:
3240 	release_sem_etc(targetAddressSpace->virtual_map.sem, WRITE_COUNT, 0);
3241 err3:
3242 	// insert the area again into the source address space
3243 	acquire_sem_etc(sourceAddressSpace->virtual_map.sem, WRITE_COUNT, 0, 0);
3244 	// check to see if this aspace has entered DELETE state
3245 	if (sourceAddressSpace->state == VM_ASPACE_STATE_DELETION
3246 		|| insert_area(sourceAddressSpace, &reservedAddress, B_EXACT_ADDRESS, area->size, area) != B_OK) {
3247 		// We can't insert the area anymore - we have to delete it manually
3248 		vm_cache_remove_area(area->cache_ref, area);
3249 		vm_cache_release_ref(area->cache_ref);
3250 		free(area->name);
3251 		free(area);
3252 		area = NULL;
3253 	}
3254 	release_sem_etc(sourceAddressSpace->virtual_map.sem, WRITE_COUNT, 0);
3255 err2:
3256 	vm_put_aspace(targetAddressSpace);
3257 err1:
3258 	if (area != NULL)
3259 		vm_put_area(area);
3260 	return status;
3261 }
3262 
3263 
3264 area_id
3265 map_physical_memory(const char *name, void *physicalAddress, size_t numBytes,
3266 	uint32 addressSpec, uint32 protection, void **_virtualAddress)
3267 {
3268 	if (!arch_vm_supports_protection(protection))
3269 		return B_NOT_SUPPORTED;
3270 
3271 	fix_protection(&protection);
3272 
3273 	return vm_map_physical_memory(vm_get_kernel_aspace_id(), name, _virtualAddress,
3274 		addressSpec, numBytes, protection, (addr_t)physicalAddress);
3275 }
3276 
3277 
3278 area_id
3279 clone_area(const char *name, void **_address, uint32 addressSpec, uint32 protection,
3280 	area_id source)
3281 {
3282 	if ((protection & B_KERNEL_PROTECTION) == 0)
3283 		protection |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA;
3284 
3285 	return vm_clone_area(vm_get_kernel_aspace_id(), name, _address, addressSpec,
3286 				protection, REGION_NO_PRIVATE_MAP, source);
3287 }
3288 
3289 
3290 area_id
3291 create_area_etc(struct team *team, const char *name, void **address, uint32 addressSpec,
3292 	uint32 size, uint32 lock, uint32 protection)
3293 {
3294 	fix_protection(&protection);
3295 
3296 	return vm_create_anonymous_area(team->aspace->id, (char *)name, address,
3297 				addressSpec, size, lock, protection);
3298 }
3299 
3300 
3301 area_id
3302 create_area(const char *name, void **_address, uint32 addressSpec, size_t size, uint32 lock,
3303 	uint32 protection)
3304 {
3305 	fix_protection(&protection);
3306 
3307 	return vm_create_anonymous_area(vm_get_kernel_aspace_id(), (char *)name, _address,
3308 				addressSpec, size, lock, protection);
3309 }
3310 
3311 
3312 status_t
3313 delete_area_etc(struct team *team, area_id area)
3314 {
3315 	return vm_delete_area(team->aspace->id, area);
3316 }
3317 
3318 
3319 status_t
3320 delete_area(area_id area)
3321 {
3322 	return vm_delete_area(vm_get_kernel_aspace_id(), area);
3323 }
3324 
3325 
3326 //	#pragma mark -
3327 
3328 
3329 status_t
3330 _user_init_heap_address_range(addr_t base, addr_t size)
3331 {
3332 	return vm_reserve_address_range(vm_get_current_user_aspace_id(), (void **)&base,
3333 		B_EXACT_ADDRESS, size, RESERVED_AVOID_BASE);
3334 }
3335 
3336 
3337 area_id
3338 _user_area_for(void *address)
3339 {
3340 	return vm_area_for(vm_get_current_user_aspace_id(), (addr_t)address);
3341 }
3342 
3343 
3344 area_id
3345 _user_find_area(const char *userName)
3346 {
3347 	char name[B_OS_NAME_LENGTH];
3348 
3349 	if (!IS_USER_ADDRESS(userName)
3350 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
3351 		return B_BAD_ADDRESS;
3352 
3353 	return find_area(name);
3354 }
3355 
3356 
3357 status_t
3358 _user_get_area_info(area_id area, area_info *userInfo)
3359 {
3360 	area_info info;
3361 	status_t status;
3362 
3363 	if (!IS_USER_ADDRESS(userInfo))
3364 		return B_BAD_ADDRESS;
3365 
3366 	status = get_area_info(area, &info);
3367 	if (status < B_OK)
3368 		return status;
3369 
3370 	if (user_memcpy(userInfo, &info, sizeof(area_info)) < B_OK)
3371 		return B_BAD_ADDRESS;
3372 
3373 	return status;
3374 }
3375 
3376 
3377 status_t
3378 _user_get_next_area_info(team_id team, int32 *userCookie, area_info *userInfo)
3379 {
3380 	status_t status;
3381 	area_info info;
3382 	int32 cookie;
3383 
3384 	if (!IS_USER_ADDRESS(userCookie)
3385 		|| !IS_USER_ADDRESS(userInfo)
3386 		|| user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK)
3387 		return B_BAD_ADDRESS;
3388 
3389 	status = _get_next_area_info(team, &cookie, &info, sizeof(area_info));
3390 	if (status != B_OK)
3391 		return status;
3392 
3393 	if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK
3394 		|| user_memcpy(userInfo, &info, sizeof(area_info)) < B_OK)
3395 		return B_BAD_ADDRESS;
3396 
3397 	return status;
3398 }
3399 
3400 
3401 status_t
3402 _user_set_area_protection(area_id area, uint32 newProtection)
3403 {
3404 	if ((newProtection & ~B_USER_PROTECTION) != 0)
3405 		return B_BAD_VALUE;
3406 
3407 	fix_protection(&newProtection);
3408 
3409 	return vm_set_area_protection(vm_get_current_user_aspace_id(), area,
3410 		newProtection);
3411 }
3412 
3413 
3414 status_t
3415 _user_resize_area(area_id area, size_t newSize)
3416 {
3417 	// ToDo: Since we restrict deleting of areas to those owned by the team,
3418 	// we should also do that for resizing (check other functions, too).
3419 	return resize_area(area, newSize);
3420 }
3421 
3422 
3423 status_t
3424 _user_transfer_area(area_id area, void **userAddress, uint32 addressSpec, team_id target)
3425 {
3426 	status_t status;
3427 	void *address;
3428 
3429 	// filter out some unavailable values (for userland)
3430 	switch (addressSpec) {
3431 		case B_ANY_KERNEL_ADDRESS:
3432 		case B_ANY_KERNEL_BLOCK_ADDRESS:
3433 			return B_BAD_VALUE;
3434 	}
3435 
3436 	if (!IS_USER_ADDRESS(userAddress)
3437 		|| user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
3438 		return B_BAD_ADDRESS;
3439 
3440 	status = transfer_area(area, &address, addressSpec, target);
3441 	if (status < B_OK)
3442 		return status;
3443 
3444 	if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK)
3445 		return B_BAD_ADDRESS;
3446 
3447 	return status;
3448 }
3449 
3450 
3451 area_id
3452 _user_clone_area(const char *userName, void **userAddress, uint32 addressSpec,
3453 	uint32 protection, area_id sourceArea)
3454 {
3455 	char name[B_OS_NAME_LENGTH];
3456 	void *address;
3457 	area_id clonedArea;
3458 
3459 	// filter out some unavailable values (for userland)
3460 	switch (addressSpec) {
3461 		case B_ANY_KERNEL_ADDRESS:
3462 		case B_ANY_KERNEL_BLOCK_ADDRESS:
3463 			return B_BAD_VALUE;
3464 	}
3465 	if ((protection & ~B_USER_PROTECTION) != 0)
3466 		return B_BAD_VALUE;
3467 
3468 	if (!IS_USER_ADDRESS(userName)
3469 		|| !IS_USER_ADDRESS(userAddress)
3470 		|| user_strlcpy(name, userName, sizeof(name)) < B_OK
3471 		|| user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
3472 		return B_BAD_ADDRESS;
3473 
3474 	fix_protection(&protection);
3475 
3476 	clonedArea = vm_clone_area(vm_get_current_user_aspace_id(), name, &address,
3477 		addressSpec, protection, REGION_NO_PRIVATE_MAP, sourceArea);
3478 	if (clonedArea < B_OK)
3479 		return clonedArea;
3480 
3481 	if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK) {
3482 		delete_area(clonedArea);
3483 		return B_BAD_ADDRESS;
3484 	}
3485 
3486 	return clonedArea;
3487 }
3488 
3489 
3490 area_id
3491 _user_create_area(const char *userName, void **userAddress, uint32 addressSpec,
3492 	size_t size, uint32 lock, uint32 protection)
3493 {
3494 	char name[B_OS_NAME_LENGTH];
3495 	area_id area;
3496 	void *address;
3497 
3498 	// filter out some unavailable values (for userland)
3499 	switch (addressSpec) {
3500 		case B_ANY_KERNEL_ADDRESS:
3501 		case B_ANY_KERNEL_BLOCK_ADDRESS:
3502 			return B_BAD_VALUE;
3503 	}
3504 	if ((protection & ~B_USER_PROTECTION) != 0)
3505 		return B_BAD_VALUE;
3506 
3507 	if (!IS_USER_ADDRESS(userName)
3508 		|| !IS_USER_ADDRESS(userAddress)
3509 		|| user_strlcpy(name, userName, sizeof(name)) < B_OK
3510 		|| user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
3511 		return B_BAD_ADDRESS;
3512 
3513 	if (addressSpec == B_EXACT_ADDRESS
3514 		&& IS_KERNEL_ADDRESS(address))
3515 		return B_BAD_VALUE;
3516 
3517 	fix_protection(&protection);
3518 
3519 	area = vm_create_anonymous_area(vm_get_current_user_aspace_id(), (char *)name, &address,
3520 				addressSpec, size, lock, protection);
3521 
3522 	if (area >= B_OK && user_memcpy(userAddress, &address, sizeof(address)) < B_OK) {
3523 		delete_area(area);
3524 		return B_BAD_ADDRESS;
3525 	}
3526 
3527 	return area;
3528 }
3529 
3530 
3531 status_t
3532 _user_delete_area(area_id area)
3533 {
3534 	// Unlike the BeOS implementation, you can now only delete areas
3535 	// that you have created yourself from userland.
3536 	// The documentation to delete_area() explicetly states that this
3537 	// will be restricted in the future, and so it will.
3538 	return vm_delete_area(vm_get_current_user_aspace_id(), area);
3539 }
3540 
3541