2 ** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
5 #include <kernel/kernel.h>
7 #include <kernel/vm_priv.h>
8 #include <kernel/vm_page.h>
9 #include <kernel/vm_cache.h>
10 #include <kernel/vm_store_anonymous_noswap.h>
11 #include <kernel/vm_store_device.h>
12 #include <kernel/vm_store_null.h>
13 #include <kernel/vm_store_vnode.h>
14 #include <kernel/heap.h>
15 #include <kernel/debug.h>
16 #include <kernel/console.h>
17 #include <kernel/int.h>
18 #include <kernel/smp.h>
19 #include <kernel/sem.h>
20 #include <kernel/lock.h>
21 #include <kernel/khash.h>
22 #include <kernel/time.h>
23 #include <newos/errors.h>
25 #include <boot/stage2.h>
27 #include <kernel/arch/cpu.h>
28 #include <kernel/arch/vm.h>
36 /* global data about the vm, used for informational purposes */
39 static vm_address_space
*kernel_aspace
;
41 #define REGION_HASH_TABLE_SIZE 1024
42 static region_id next_region_id
;
43 static void *region_table
;
44 static sem_id region_hash_sem
;
46 #define ASPACE_HASH_TABLE_SIZE 1024
47 static aspace_id next_aspace_id
;
48 static void *aspace_table
;
49 static sem_id aspace_hash_sem
;
51 static int max_commit
;
52 static spinlock_t max_commit_lock
;
54 // function declarations
55 static vm_region
*_vm_create_region_struct(vm_address_space
*aspace
, const char *name
, int wiring
, int lock
);
56 static int map_backing_store(vm_address_space
*aspace
, vm_store
*store
, void **vaddr
,
57 off_t offset
, addr_t size
, int addr_type
, int wiring
, int lock
, int mapping
, vm_region
**_region
, const char *region_name
);
58 static int vm_soft_fault(addr_t address
, bool is_write
, bool is_user
);
59 static vm_region
*vm_virtual_map_lookup(vm_virtual_map
*map
, addr_t address
);
61 static int region_compare(void *_r
, const void *key
)
64 const region_id
*id
= key
;
76 static unsigned int region_hash(void *_r
, const void *key
, unsigned int range
)
79 const region_id
*id
= key
;
87 return (r
->id
% range
);
92 static int aspace_compare(void *_a
, const void *key
)
94 vm_address_space
*aspace
= _a
;
95 const aspace_id
*id
= key
;
98 VERIFY_VM_ASPACE(aspace
);
101 if(aspace
->id
== *id
)
107 static unsigned int aspace_hash(void *_a
, const void *key
, unsigned int range
)
109 vm_address_space
*aspace
= _a
;
110 const aspace_id
*id
= key
;
114 VERIFY_VM_ASPACE(aspace
);
118 return (aspace
->id
% range
);
120 return (*id
% range
);
123 vm_address_space
*vm_get_aspace_by_id(aspace_id aid
)
125 vm_address_space
*aspace
;
127 sem_acquire(aspace_hash_sem
, READ_COUNT
);
128 aspace
= hash_lookup(aspace_table
, &aid
);
130 VERIFY_VM_ASPACE(aspace
);
131 atomic_add(&aspace
->ref_count
, 1);
133 sem_release(aspace_hash_sem
, READ_COUNT
);
138 vm_region
*vm_get_region_by_id(region_id rid
)
142 sem_acquire(region_hash_sem
, READ_COUNT
);
143 region
= hash_lookup(region_table
, &rid
);
145 VERIFY_VM_REGION(region
);
146 atomic_add(®ion
->ref_count
, 1);
148 sem_release(region_hash_sem
, READ_COUNT
);
153 region_id
vm_find_region_by_name(aspace_id aid
, const char *name
)
155 vm_region
*region
= NULL
;
156 vm_address_space
*aspace
;
157 region_id id
= ERR_NOT_FOUND
;
159 ASSERT(name
!= NULL
);
161 aspace
= vm_get_aspace_by_id(aid
);
163 return ERR_VM_INVALID_ASPACE
;
165 sem_acquire(aspace
->virtual_map
.sem
, READ_COUNT
);
167 region
= aspace
->virtual_map
.region_list
;
168 while(region
!= NULL
) {
169 VERIFY_VM_REGION(region
);
170 ASSERT(region
->name
!= NULL
);
171 if(strcmp(region
->name
, name
) == 0) {
175 region
= region
->aspace_next
;
178 sem_release(aspace
->virtual_map
.sem
, READ_COUNT
);
179 vm_put_aspace(aspace
);
183 static vm_region
*_vm_create_region_struct(vm_address_space
*aspace
, const char *name
, int wiring
, int lock
)
185 vm_region
*region
= NULL
;
187 VERIFY_VM_ASPACE(aspace
);
188 ASSERT(name
!= NULL
);
190 region
= (vm_region
*)kmalloc(sizeof(vm_region
));
193 region
->name
= (char *)kmalloc(strlen(name
) + 1);
194 if(region
->name
== NULL
) {
198 strcpy(region
->name
, name
);
199 region
->magic
= VM_REGION_MAGIC
;
200 region
->id
= atomic_add(&next_region_id
, 1);
204 region
->wiring
= wiring
;
205 region
->ref_count
= 1;
207 region
->cache_ref
= NULL
;
208 region
->cache_offset
= 0;
210 region
->aspace
= aspace
;
211 region
->aspace_next
= NULL
;
212 region
->map
= &aspace
->virtual_map
;
213 region
->cache_next
= region
->cache_prev
= NULL
;
214 region
->hash_next
= NULL
;
219 // must be called with this address space's virtual_map.sem held
220 static int find_and_insert_region_slot(vm_virtual_map
*map
, addr_t start
, addr_t size
, addr_t end
, int addr_type
, vm_region
*region
)
222 vm_region
*last_r
= NULL
;
224 bool foundspot
= false;
226 dprintf("find_and_insert_region_slot: map %p, start 0x%lx, size %ld, end 0x%lx, addr_type %d, region %p\n",
227 map
, start
, size
, end
, addr_type
, region
);
228 // dprintf("map->base 0x%x, map->size 0x%x\n", map->base, map->size);
230 // do some sanity checking
231 if(start
< map
->base
|| size
== 0 || (end
- 1) > (map
->base
+ (map
->size
- 1)) || start
+ size
> end
)
232 return ERR_VM_BAD_ADDRESS
;
234 // walk up to the spot where we should start searching
235 next_r
= map
->region_list
;
237 if(next_r
->base
>= start
+ size
) {
242 next_r
= next_r
->aspace_next
;
246 dprintf("last_r 0x%x, next_r 0x%x\n", last_r
, next_r
);
247 if(last_r
) dprintf("last_r->base 0x%x, last_r->size 0x%x\n", last_r
->base
, last_r
->size
);
248 if(next_r
) dprintf("next_r->base 0x%x, next_r->size 0x%x\n", next_r
->base
, next_r
->size
);
252 case REGION_ADDR_ANY_ADDRESS
:
253 // find a hole big enough for a new region
255 // see if we can build it at the beginning of the virtual map
256 if(!next_r
|| (next_r
->base
>= map
->base
+ size
)) {
258 region
->base
= map
->base
;
262 next_r
= next_r
->aspace_next
;
266 if(next_r
->base
>= last_r
->base
+ last_r
->size
+ size
) {
269 region
->base
= last_r
->base
+ last_r
->size
;
273 next_r
= next_r
->aspace_next
;
275 if((map
->base
+ (map
->size
- 1)) >= (last_r
->base
+ last_r
->size
+ (size
- 1))) {
278 region
->base
= last_r
->base
+ last_r
->size
;
282 case REGION_ADDR_EXACT_ADDRESS
:
283 // see if we can create it exactly here
285 if(!next_r
|| (next_r
->base
>= start
+ size
)) {
287 region
->base
= start
;
292 if(last_r
->base
+ last_r
->size
<= start
&& next_r
->base
>= start
+ size
) {
294 region
->base
= start
;
298 if((last_r
->base
+ (last_r
->size
- 1)) <= start
- 1) {
300 region
->base
= start
;
306 return ERR_INVALID_ARGS
;
312 region
->aspace_next
= last_r
->aspace_next
;
313 last_r
->aspace_next
= region
;
315 region
->aspace_next
= map
->region_list
;
316 map
->region_list
= region
;
321 return ERR_VM_NO_REGION_SLOT
;
325 // a ref to the cache holding this store must be held before entering here
326 static int map_backing_store(vm_address_space
*aspace
, vm_store
*store
, void **vaddr
,
327 off_t offset
, addr_t size
, int addr_type
, int wiring
, int lock
, int mapping
, vm_region
**_region
, const char *region_name
)
330 vm_cache_ref
*cache_ref
;
333 vm_cache_ref
*nu_cache_ref
= NULL
;
338 VERIFY_VM_ASPACE(aspace
);
339 VERIFY_VM_STORE(store
);
341 // dprintf("map_backing_store: aspace %p, store %p, *vaddr %p, offset 0x%Lx, size 0x%lx, addr_type %d, wiring %d, lock %d, _region %p, region_name '%s'\n",
342 // aspace, store, *vaddr, offset, size, addr_type, wiring, lock, _region, region_name);
344 region
= _vm_create_region_struct(aspace
, region_name
, wiring
, lock
);
346 return ERR_NO_MEMORY
;
348 cache
= store
->cache
;
349 VERIFY_VM_CACHE(cache
);
350 cache_ref
= cache
->ref
;
351 VERIFY_VM_CACHE_REF(cache_ref
);
353 // if this is a private map, we need to create a new cache & store object
354 // pair to handle the private copies of pages as they are written to
355 if(mapping
== REGION_PRIVATE_MAP
) {
356 // create an anonymous store object
357 nu_store
= vm_store_create_anonymous_noswap();
359 panic("map_backing_store: vm_create_store_anonymous_noswap returned NULL");
360 nu_cache
= vm_cache_create(nu_store
);
362 panic("map_backing_store: vm_cache_create returned NULL");
363 nu_cache_ref
= vm_cache_ref_create(nu_cache
);
364 if(nu_cache_ref
== NULL
)
365 panic("map_backing_store: vm_cache_ref_create returned NULL");
366 nu_cache
->temporary
= 1;
367 nu_cache
->scan_skip
= cache
->scan_skip
;
369 nu_cache
->source
= cache
;
371 // grab a ref to the cache object we're now linked to as a source
372 vm_cache_acquire_ref(cache_ref
, true);
375 cache_ref
= cache
->ref
;
379 mutex_lock(&cache_ref
->lock
);
380 if(store
->committed_size
< offset
+ size
) {
381 // try to commit more memory
382 off_t old_store_commitment
= store
->committed_size
;
383 off_t commitment
= (store
->ops
->commit
)(store
, offset
+ size
);
384 if(commitment
< offset
+ size
) {
385 if(cache
->temporary
) {
386 int_disable_interrupts();
387 acquire_spinlock(&max_commit_lock
);
389 if(max_commit
- old_store_commitment
+ commitment
< offset
+ size
) {
390 release_spinlock(&max_commit_lock
);
391 int_restore_interrupts();
392 mutex_unlock(&cache_ref
->lock
);
393 err
= ERR_VM_WOULD_OVERCOMMIT
;
397 // dprintf("map_backing_store: adding %d to max_commit\n",
398 // (commitment - old_store_commitment) - (offset + size - cache->committed_size));
400 max_commit
+= (commitment
- old_store_commitment
) - (offset
+ size
- cache
->virtual_size
);
401 cache
->virtual_size
= offset
+ size
;
402 release_spinlock(&max_commit_lock
);
403 int_restore_interrupts();
405 mutex_unlock(&cache_ref
->lock
);
412 mutex_unlock(&cache_ref
->lock
);
414 vm_cache_acquire_ref(cache_ref
, true);
416 sem_acquire(aspace
->virtual_map
.sem
, WRITE_COUNT
);
418 // check to see if this aspace has entered DELETE state
419 if(aspace
->state
== VM_ASPACE_STATE_DELETION
) {
420 // okay, someone is trying to delete this aspace now, so we can't
421 // insert the region, so back out
422 err
= ERR_VM_INVALID_ASPACE
;
427 addr_t search_addr
, search_end
;
429 if(addr_type
== REGION_ADDR_EXACT_ADDRESS
) {
430 search_addr
= (addr_t
)*vaddr
;
431 search_end
= (addr_t
)*vaddr
+ size
;
432 } else if(addr_type
== REGION_ADDR_ANY_ADDRESS
) {
433 search_addr
= aspace
->virtual_map
.base
;
434 search_end
= aspace
->virtual_map
.base
+ (aspace
->virtual_map
.size
- 1);
436 err
= ERR_INVALID_ARGS
;
440 err
= find_and_insert_region_slot(&aspace
->virtual_map
, search_addr
, size
, search_end
, addr_type
, region
);
443 *vaddr
= (addr_t
*)region
->base
;
446 // attach the cache to the region
447 region
->cache_ref
= cache_ref
;
448 region
->cache_offset
= offset
;
449 // point the cache back to the region
450 vm_cache_insert_region(cache_ref
, region
);
452 // insert the region in the global region hash table
453 sem_acquire(region_hash_sem
, WRITE_COUNT
);
454 hash_insert(region_table
, region
);
455 sem_release(region_hash_sem
, WRITE_COUNT
);
457 // grab a ref to the aspace (the region holds this)
458 atomic_add(&aspace
->ref_count
, 1);
460 sem_release(aspace
->virtual_map
.sem
, WRITE_COUNT
);
467 sem_release(aspace
->virtual_map
.sem
, WRITE_COUNT
);
468 vm_cache_release_ref(cache_ref
);
472 // had never acquired it's initial ref, so acquire and then release it
473 // this should clean up all the objects it references
474 vm_cache_acquire_ref(cache_ref
, true);
475 vm_cache_release_ref(cache_ref
);
483 region_id
user_vm_create_anonymous_region(char *uname
, void **uaddress
, int addr_type
,
484 addr_t size
, int wiring
, int lock
)
486 char name
[SYS_MAX_OS_NAME_LEN
];
490 if((addr_t
)uname
>= KERNEL_BASE
&& (addr_t
)uname
<= KERNEL_TOP
)
491 return ERR_VM_BAD_USER_MEMORY
;
493 rc
= user_strncpy(name
, uname
, SYS_MAX_OS_NAME_LEN
-1);
496 name
[SYS_MAX_OS_NAME_LEN
-1] = 0;
498 rc
= user_memcpy(&address
, uaddress
, sizeof(address
));
502 rc
= vm_create_anonymous_region(vm_get_current_user_aspace_id(), name
, &address
, addr_type
, size
, wiring
, lock
);
506 rc2
= user_memcpy(uaddress
, &address
, sizeof(address
));
513 region_id
vm_create_anonymous_region(aspace_id aid
, char *name
, void **address
, int addr_type
,
514 addr_t size
, int wiring
, int lock
)
520 vm_address_space
*aspace
;
521 vm_cache_ref
*cache_ref
;
523 dprintf("create_anonymous_region: name '%s', type %d, size 0x%lx, wiring %d, lock %d\n",
524 name
, addr_type
, size
, wiring
, lock
);
526 if(addr_type
!= REGION_ADDR_ANY_ADDRESS
&& addr_type
!= REGION_ADDR_EXACT_ADDRESS
)
527 return ERR_INVALID_ARGS
;
529 case REGION_WIRING_WIRED
:
530 case REGION_WIRING_WIRED_ALREADY
:
531 case REGION_WIRING_WIRED_CONTIG
:
532 case REGION_WIRING_LAZY
:
535 return ERR_INVALID_ARGS
;
537 aspace
= vm_get_aspace_by_id(aid
);
539 return ERR_VM_INVALID_ASPACE
;
541 size
= PAGE_ALIGN(size
);
543 // create an anonymous store object
544 store
= vm_store_create_anonymous_noswap();
546 panic("vm_create_anonymous_region: vm_create_store_anonymous_noswap returned NULL");
547 cache
= vm_cache_create(store
);
549 panic("vm_create_anonymous_region: vm_cache_create returned NULL");
550 cache_ref
= vm_cache_ref_create(cache
);
551 if(cache_ref
== NULL
)
552 panic("vm_create_anonymous_region: vm_cache_ref_create returned NULL");
553 cache
->temporary
= 1;
556 case REGION_WIRING_WIRED
:
557 case REGION_WIRING_WIRED_ALREADY
:
558 case REGION_WIRING_WIRED_CONTIG
:
559 cache
->scan_skip
= 1;
561 case REGION_WIRING_LAZY
:
562 cache
->scan_skip
= 0;
566 // dprintf("create_anonymous_region: calling map_backing store\n");
568 vm_cache_acquire_ref(cache_ref
, true);
569 err
= map_backing_store(aspace
, store
, address
, 0, size
, addr_type
, wiring
, lock
, REGION_NO_PRIVATE_MAP
, ®ion
, name
);
570 vm_cache_release_ref(cache_ref
);
572 vm_put_aspace(aspace
);
576 // dprintf("create_anonymous_region: done calling map_backing store\n");
578 cache_ref
= store
->cache
->ref
;
580 case REGION_WIRING_LAZY
:
582 case REGION_WIRING_WIRED
: {
583 // pages aren't mapped at this point, but we just simulate a fault on
584 // every page, which should allocate them
587 for(va
= region
->base
; va
< region
->base
+ region
->size
; va
+= PAGE_SIZE
) {
588 dprintf("mapping wired pages: region %p, cache_ref %p %p, address 0x%lx\n", region
, cache_ref
, region
->cache_ref
, va
);
589 vm_soft_fault(va
, false, false);
593 case REGION_WIRING_WIRED_ALREADY
: {
594 // the pages should already be mapped. This is only really useful during
595 // boot time. Find the appropriate vm_page objects and stick them in
604 mutex_lock(&cache_ref
->lock
);
605 (*aspace
->translation_map
.ops
->lock
)(&aspace
->translation_map
);
606 for(va
= region
->base
; va
< region
->base
+ region
->size
; va
+= PAGE_SIZE
, offset
+= PAGE_SIZE
) {
607 err
= (*aspace
->translation_map
.ops
->query
)(&aspace
->translation_map
,
610 // dprintf("vm_create_anonymous_region: error looking up mapping for va 0x%x\n", va);
613 // dprintf("vm_create_anonymous_region: looked up page at va 0x%lx. pa 0x%lx\n", va, pa);
614 page
= vm_lookup_page(pa
/ PAGE_SIZE
);
616 // dprintf("vm_create_anonymous_region: error looking up vm_page structure for pa 0x%x\n", pa);
619 atomic_add(&page
->ref_count
, 1);
620 vm_page_set_state(page
, PAGE_STATE_WIRED
);
621 vm_cache_insert_page(cache_ref
, page
, offset
);
623 (*aspace
->translation_map
.ops
->unlock
)(&aspace
->translation_map
);
624 mutex_unlock(&cache_ref
->lock
);
627 case REGION_WIRING_WIRED_CONTIG
: {
634 page
= vm_page_allocate_page_run(PAGE_STATE_CLEAR
, ROUNDUP(region
->size
, PAGE_SIZE
) / PAGE_SIZE
);
636 // XXX back out of this
637 panic("couldn't allocate page run of size %ld\n", region
->size
);
639 phys_addr
= page
->ppn
* PAGE_SIZE
;
641 mutex_lock(&cache_ref
->lock
);
642 (*aspace
->translation_map
.ops
->lock
)(&aspace
->translation_map
);
643 for(va
= region
->base
; va
< region
->base
+ region
->size
; va
+= PAGE_SIZE
, offset
+= PAGE_SIZE
, phys_addr
+= PAGE_SIZE
) {
644 page
= vm_lookup_page(phys_addr
/ PAGE_SIZE
);
646 panic("couldn't lookup physical page just allocated\n");
648 atomic_add(&page
->ref_count
, 1);
649 err
= (*aspace
->translation_map
.ops
->map
)(&aspace
->translation_map
, va
, phys_addr
, lock
);
651 panic("couldn't map physical page in page run\n");
653 vm_page_set_state(page
, PAGE_STATE_WIRED
);
654 vm_cache_insert_page(cache_ref
, page
, offset
);
656 (*aspace
->translation_map
.ops
->unlock
)(&aspace
->translation_map
);
657 mutex_unlock(&cache_ref
->lock
);
664 vm_put_aspace(aspace
);
665 dprintf("create_anonymous_region: done\n");
669 return ERR_NO_MEMORY
;
672 region_id
vm_map_physical_memory(aspace_id aid
, char *name
, void **address
, int addr_type
,
673 addr_t size
, int lock
, addr_t phys_addr
)
677 vm_cache_ref
*cache_ref
;
682 vm_address_space
*aspace
= vm_get_aspace_by_id(aid
);
684 return ERR_VM_INVALID_ASPACE
;
686 // if the physical address is somewhat inside a page,
687 // move the actual region down to align on a page boundary
688 map_offset
= phys_addr
% PAGE_SIZE
;
690 phys_addr
-= map_offset
;
692 size
= PAGE_ALIGN(size
);
694 // create an device store object
695 store
= vm_store_create_device(phys_addr
);
697 panic("vm_map_physical_memory: vm_store_create_device returned NULL");
698 cache
= vm_cache_create(store
);
700 panic("vm_map_physical_memory: vm_cache_create returned NULL");
701 cache_ref
= vm_cache_ref_create(cache
);
702 if(cache_ref
== NULL
)
703 panic("vm_map_physical_memory: vm_cache_ref_create returned NULL");
705 // tell the page scanner to skip over this region, it's pages are special
706 cache
->scan_skip
= 1;
708 vm_cache_acquire_ref(cache_ref
, true);
709 err
= map_backing_store(aspace
, store
, address
, 0, size
, addr_type
, 0, lock
, REGION_NO_PRIVATE_MAP
, ®ion
, name
);
710 vm_cache_release_ref(cache_ref
);
711 vm_put_aspace(aspace
);
716 // modify the pointer returned to be offset back into the new region
717 // the same way the physical address in was offset
718 ((addr_t
)(*address
)) += map_offset
;
722 region_id
vm_create_null_region(aspace_id aid
, char *name
, void **address
, int addr_type
, addr_t size
)
726 vm_cache_ref
*cache_ref
;
730 vm_address_space
*aspace
= vm_get_aspace_by_id(aid
);
732 return ERR_VM_INVALID_ASPACE
;
734 size
= PAGE_ALIGN(size
);
736 // create an null store object
737 store
= vm_store_create_null();
739 panic("vm_create_null_region: vm_store_create_null returned NULL");
740 cache
= vm_cache_create(store
);
742 panic("vm_create_null_region: vm_cache_create returned NULL");
743 cache_ref
= vm_cache_ref_create(cache
);
744 if(cache_ref
== NULL
)
745 panic("vm_create_null_region: vm_cache_ref_create returned NULL");
746 // tell the page scanner to skip over this region, no pages will be mapped here
747 cache
->scan_skip
= 1;
749 vm_cache_acquire_ref(cache_ref
, true);
750 err
= map_backing_store(aspace
, store
, address
, 0, size
, addr_type
, 0, LOCK_RO
, REGION_NO_PRIVATE_MAP
, ®ion
, name
);
751 vm_cache_release_ref(cache_ref
);
752 vm_put_aspace(aspace
);
759 static region_id
_vm_map_file(aspace_id aid
, char *name
, void **address
, int addr_type
,
760 addr_t size
, int lock
, int mapping
, const char *path
, off_t offset
, bool kernel
)
764 vm_cache_ref
*cache_ref
;
769 vm_address_space
*aspace
= vm_get_aspace_by_id(aid
);
771 return ERR_VM_INVALID_ASPACE
;
773 offset
= ROUNDOWN(offset
, PAGE_SIZE
);
774 size
= PAGE_ALIGN(size
);
777 // get the vnode for the object, this also grabs a ref to it
778 err
= vfs_get_vnode_from_path(path
, kernel
, &v
);
780 vm_put_aspace(aspace
);
784 cache_ref
= vfs_get_cache_ptr(v
);
786 // create a vnode store object
787 store
= vm_store_create_vnode(v
);
789 panic("vm_map_file: couldn't create vnode store");
790 cache
= vm_cache_create(store
);
792 panic("vm_map_physical_memory: vm_cache_create returned NULL");
793 cache_ref
= vm_cache_ref_create(cache
);
794 if(cache_ref
== NULL
)
795 panic("vm_map_physical_memory: vm_cache_ref_create returned NULL");
797 // acquire the cache ref once to represent the ref that the vnode will have
798 // this is one of the only places where we dont want to ref to ripple down to the store
799 vm_cache_acquire_ref(cache_ref
, false);
801 // try to set the cache ptr in the vnode
802 if(vfs_set_cache_ptr(v
, cache_ref
) < 0) {
803 // the cache pointer was set between here and then
804 // this can only happen if someone else tries to map it
805 // at the same time. Rare enough to not worry about the
806 // performance impact of undoing what we just did and retrying
808 // this will delete the cache object and release the ref to the vnode we have
809 vm_cache_release_ref(cache_ref
);
813 VERIFY_VM_CACHE_REF(cache_ref
);
814 cache
= cache_ref
->cache
;
815 VERIFY_VM_CACHE(cache
);
816 store
= cache
->store
;
817 VERIFY_VM_STORE(store
);
820 // acquire a ref to the cache before we do work on it. Dont ripple the ref acquision to the vnode
821 // below because we'll have to release it later anyway, since we grabbed a ref to the vnode at
822 // vfs_get_vnode_from_path(). This puts the ref counts in sync.
823 vm_cache_acquire_ref(cache_ref
, false);
824 err
= map_backing_store(aspace
, store
, address
, offset
, size
, addr_type
, 0, lock
, mapping
, ®ion
, name
);
825 vm_cache_release_ref(cache_ref
);
826 vm_put_aspace(aspace
);
830 // modify the pointer returned to be offset back into the new region
831 // the same way the physical address in was offset
835 region_id
vm_map_file(aspace_id aid
, char *name
, void **address
, int addr_type
,
836 addr_t size
, int lock
, int mapping
, const char *path
, off_t offset
)
838 return _vm_map_file(aid
, name
, address
, addr_type
, size
, lock
, mapping
, path
, offset
, true);
841 region_id
user_vm_map_file(char *uname
, void **uaddress
, int addr_type
,
842 addr_t size
, int lock
, int mapping
, const char *upath
, off_t offset
)
844 char name
[SYS_MAX_OS_NAME_LEN
];
846 char path
[SYS_MAX_PATH_LEN
];
849 if((addr_t
)uname
>= KERNEL_BASE
&& (addr_t
)uname
<= KERNEL_TOP
)
850 return ERR_VM_BAD_USER_MEMORY
;
852 if((addr_t
)uaddress
>= KERNEL_BASE
&& (addr_t
)uaddress
<= KERNEL_TOP
)
853 return ERR_VM_BAD_USER_MEMORY
;
855 if((addr_t
)upath
>= KERNEL_BASE
&& (addr_t
)upath
<= KERNEL_TOP
)
856 return ERR_VM_BAD_USER_MEMORY
;
858 rc
= user_strncpy(name
, uname
, SYS_MAX_OS_NAME_LEN
-1);
861 name
[SYS_MAX_OS_NAME_LEN
-1] = 0;
863 rc
= user_strncpy(path
, upath
, SYS_MAX_PATH_LEN
-1);
866 path
[SYS_MAX_PATH_LEN
-1] = 0;
868 rc
= user_memcpy(&address
, uaddress
, sizeof(address
));
872 rc
= _vm_map_file(vm_get_current_user_aspace_id(), name
, &address
, addr_type
, size
, lock
, mapping
, path
, offset
, false);
876 rc2
= user_memcpy(uaddress
, &address
, sizeof(address
));
883 region_id
user_vm_clone_region(char *uname
, void **uaddress
, int addr_type
,
884 region_id source_region
, int mapping
, int lock
)
886 char name
[SYS_MAX_OS_NAME_LEN
];
890 if((addr_t
)uname
>= KERNEL_BASE
&& (addr_t
)uname
<= KERNEL_TOP
)
891 return ERR_VM_BAD_USER_MEMORY
;
893 if((addr_t
)uaddress
>= KERNEL_BASE
&& (addr_t
)uaddress
<= KERNEL_TOP
)
894 return ERR_VM_BAD_USER_MEMORY
;
896 rc
= user_strncpy(name
, uname
, SYS_MAX_OS_NAME_LEN
-1);
899 name
[SYS_MAX_OS_NAME_LEN
-1] = 0;
901 rc
= user_memcpy(&address
, uaddress
, sizeof(address
));
905 rc
= vm_clone_region(vm_get_current_user_aspace_id(), name
, &address
, addr_type
, source_region
, mapping
, lock
);
909 rc2
= user_memcpy(uaddress
, &address
, sizeof(address
));
916 region_id
vm_clone_region(aspace_id aid
, char *name
, void **address
, int addr_type
,
917 region_id source_region
, int mapping
, int lock
)
919 vm_region
*new_region
;
920 vm_region
*src_region
;
923 vm_address_space
*aspace
= vm_get_aspace_by_id(aid
);
925 return ERR_VM_INVALID_ASPACE
;
927 src_region
= vm_get_region_by_id(source_region
);
928 if(src_region
== NULL
) {
929 vm_put_aspace(aspace
);
930 return ERR_VM_INVALID_REGION
;
933 vm_cache_acquire_ref(src_region
->cache_ref
, true);
934 err
= map_backing_store(aspace
, src_region
->cache_ref
->cache
->store
, address
, src_region
->cache_offset
, src_region
->size
,
935 addr_type
, src_region
->wiring
, lock
, mapping
, &new_region
, name
);
936 vm_cache_release_ref(src_region
->cache_ref
);
938 // release the ref on the old region
939 vm_put_region(src_region
);
941 vm_put_aspace(aspace
);
946 return new_region
->id
;
949 static int __vm_delete_region(vm_address_space
*aspace
, vm_region
*region
)
951 VERIFY_VM_ASPACE(aspace
);
952 VERIFY_VM_REGION(region
);
954 if(region
->aspace
== aspace
)
955 vm_put_region(region
);
959 static int _vm_delete_region(vm_address_space
*aspace
, region_id rid
)
963 dprintf("vm_delete_region: aspace id 0x%x, region id 0x%x\n", aspace
->id
, rid
);
965 VERIFY_VM_ASPACE(aspace
);
967 region
= vm_get_region_by_id(rid
);
969 return ERR_VM_INVALID_REGION
;
971 __vm_delete_region(aspace
, region
);
972 vm_put_region(region
);
977 int vm_delete_region(aspace_id aid
, region_id rid
)
979 vm_address_space
*aspace
;
982 aspace
= vm_get_aspace_by_id(aid
);
984 return ERR_VM_INVALID_ASPACE
;
986 err
= _vm_delete_region(aspace
, rid
);
987 vm_put_aspace(aspace
);
991 static void _vm_put_region(vm_region
*region
, bool aspace_locked
)
993 vm_region
*temp
, *last
= NULL
;
994 vm_address_space
*aspace
;
995 bool removeit
= false;
997 VERIFY_VM_REGION(region
);
999 sem_acquire(region_hash_sem
, WRITE_COUNT
);
1000 if(atomic_add(®ion
->ref_count
, -1) == 1) {
1001 hash_remove(region_table
, region
);
1004 sem_release(region_hash_sem
, WRITE_COUNT
);
1009 aspace
= region
->aspace
;
1010 VERIFY_VM_ASPACE(aspace
);
1012 // remove the region from the aspace's virtual map
1014 sem_acquire(aspace
->virtual_map
.sem
, WRITE_COUNT
);
1015 temp
= aspace
->virtual_map
.region_list
;
1016 while(temp
!= NULL
) {
1017 if(region
== temp
) {
1019 last
->aspace_next
= temp
->aspace_next
;
1021 aspace
->virtual_map
.region_list
= temp
->aspace_next
;
1023 aspace
->virtual_map
.change_count
++;
1027 temp
= temp
->aspace_next
;
1029 if(region
== aspace
->virtual_map
.region_hint
)
1030 aspace
->virtual_map
.region_hint
= NULL
;
1032 sem_release(aspace
->virtual_map
.sem
, WRITE_COUNT
);
1035 panic("vm_region_release_ref: region not found in aspace's region_list\n");
1037 vm_cache_remove_region(region
->cache_ref
, region
);
1038 vm_cache_release_ref(region
->cache_ref
);
1040 (*aspace
->translation_map
.ops
->lock
)(&aspace
->translation_map
);
1041 (*aspace
->translation_map
.ops
->unmap
)(&aspace
->translation_map
, region
->base
,
1042 region
->base
+ (region
->size
- 1));
1043 (*aspace
->translation_map
.ops
->unlock
)(&aspace
->translation_map
);
1045 // now we can give up the last ref to the aspace
1046 vm_put_aspace(aspace
);
1049 kfree(region
->name
);
1055 void vm_put_region(vm_region
*region
)
1057 return _vm_put_region(region
, false);
1060 int user_vm_get_region_info(region_id id
, vm_region_info
*uinfo
)
1062 vm_region_info info
;
1065 if((addr_t
)uinfo
>= KERNEL_BASE
&& (addr_t
)uinfo
<= KERNEL_TOP
)
1066 return ERR_VM_BAD_USER_MEMORY
;
1068 rc
= vm_get_region_info(id
, &info
);
1072 rc2
= user_memcpy(uinfo
, &info
, sizeof(info
));
1079 int vm_get_region_info(region_id id
, vm_region_info
*info
)
1084 return ERR_INVALID_ARGS
;
1086 region
= vm_get_region_by_id(id
);
1088 return ERR_VM_INVALID_REGION
;
1090 info
->id
= region
->id
;
1091 info
->base
= region
->base
;
1092 info
->size
= region
->size
;
1093 info
->lock
= region
->lock
;
1094 info
->wiring
= region
->wiring
;
1095 strncpy(info
->name
, region
->name
, SYS_MAX_OS_NAME_LEN
-1);
1096 info
->name
[SYS_MAX_OS_NAME_LEN
-1] = 0;
1098 vm_put_region(region
);
1103 int vm_get_page_mapping(aspace_id aid
, addr_t vaddr
, addr_t
*paddr
)
1105 vm_address_space
*aspace
;
1106 unsigned int null_flags
;
1109 aspace
= vm_get_aspace_by_id(aid
);
1111 return ERR_VM_INVALID_ASPACE
;
1113 err
= aspace
->translation_map
.ops
->query(&aspace
->translation_map
,
1114 vaddr
, paddr
, &null_flags
);
1115 vm_put_aspace(aspace
);
1119 static void display_mem(int argc
, char **argv
)
1129 dprintf("not enough arguments\n");
1133 address
= atoul(argv
[1]);
1137 num
= atoi(argv
[2]);
1140 // build the format string
1141 if(strcmp(argv
[0], "db") == 0) {
1144 } else if(strcmp(argv
[0], "ds") == 0) {
1147 } else if(strcmp(argv
[0], "dw") == 0) {
1151 dprintf("display_mem called in an invalid way!\n");
1155 dprintf("[0x%lx] '", address
);
1156 for(j
=0; j
<min(display_width
, num
) * item_size
; j
++) {
1157 char c
= *((char *)address
+ j
);
1164 for(i
=0; i
<num
; i
++) {
1165 if((i
% display_width
) == 0 && i
!= 0) {
1166 dprintf("\n[0x%lx] '", address
+ i
* item_size
);
1167 for(j
=0; j
<min(display_width
, (num
-i
)) * item_size
; j
++) {
1168 char c
= *((char *)address
+ i
* item_size
+ j
);
1179 dprintf(" 0x%02x", *((uint8
*)address
+ i
));
1182 dprintf(" 0x%04x", *((uint16
*)address
+ i
));
1185 dprintf(" 0x%08x", *((uint32
*)address
+ i
));
1194 static void dump_cache_ref(int argc
, char **argv
)
1198 vm_cache_ref
*cache_ref
;
1201 dprintf("cache_ref: not enough arguments\n");
1204 if(strlen(argv
[1]) < 2 || argv
[1][0] != '0' || argv
[1][1] != 'x') {
1205 dprintf("cache_ref: invalid argument, pass address\n");
1209 address
= atoul(argv
[1]);
1210 cache_ref
= (vm_cache_ref
*)address
;
1212 dprintf("cache_ref at %p:\n", cache_ref
);
1213 dprintf("magic: 0x%x ", cache_ref
->magic
);
1214 if(cache_ref
->magic
== VM_CACHE_REF_MAGIC
)
1215 dprintf("(GOOD)\n");
1217 dprintf("(BAD!)\n");
1218 dprintf("cache: %p\n", cache_ref
->cache
);
1219 dprintf("lock.holder: %d\n", cache_ref
->lock
.holder
);
1220 dprintf("lock.sem: 0x%x\n", cache_ref
->lock
.sem
);
1221 dprintf("region_list:\n");
1222 for(region
= cache_ref
->region_list
; region
!= NULL
; region
= region
->cache_next
) {
1223 dprintf(" region 0x%x: ", region
->id
);
1224 dprintf("base_addr = 0x%lx ", region
->base
);
1225 dprintf("size = 0x%lx ", region
->size
);
1226 dprintf("name = '%s' ", region
->name
);
1227 dprintf("lock = 0x%x\n", region
->lock
);
1229 dprintf("ref_count: %d\n", cache_ref
->ref_count
);
1232 static const char *page_state_to_text(int state
)
1235 case PAGE_STATE_ACTIVE
:
1237 case PAGE_STATE_INACTIVE
:
1239 case PAGE_STATE_BUSY
:
1241 case PAGE_STATE_MODIFIED
:
1243 case PAGE_STATE_FREE
:
1245 case PAGE_STATE_CLEAR
:
1247 case PAGE_STATE_WIRED
:
1249 case PAGE_STATE_UNUSED
:
1256 static void dump_cache(int argc
, char **argv
)
1263 dprintf("cache: not enough arguments\n");
1266 if(strlen(argv
[1]) < 2 || argv
[1][0] != '0' || argv
[1][1] != 'x') {
1267 dprintf("cache: invalid argument, pass address\n");
1271 address
= atoul(argv
[1]);
1272 cache
= (vm_cache
*)address
;
1274 dprintf("cache at %p:\n", cache
);
1275 dprintf("magic: 0x%x ", cache
->magic
);
1276 if(cache
->magic
== VM_CACHE_MAGIC
)
1277 dprintf("(GOOD)\n");
1279 dprintf("(BAD!)\n");
1280 dprintf("cache_ref: %p\n", cache
->ref
);
1281 dprintf("source: %p\n", cache
->source
);
1282 dprintf("store: %p\n", cache
->store
);
1283 dprintf("temporary: %d\n", cache
->temporary
);
1284 dprintf("scan_skip: %d\n", cache
->scan_skip
);
1285 dprintf("virtual_size: 0x%Lx\n", cache
->virtual_size
);
1286 dprintf("page_list:\n");
1287 for(page
= cache
->page_list
; page
!= NULL
; page
= page
->cache_next
) {
1288 if(page
->type
== PAGE_TYPE_PHYSICAL
)
1289 dprintf(" %p ppn 0x%lx offset 0x%Lx type %d state %d (%s) ref_count %d\n",
1290 page
, page
->ppn
, page
->offset
, page
->type
, page
->state
, page_state_to_text(page
->state
), page
->ref_count
);
1291 else if(page
->type
== PAGE_TYPE_DUMMY
)
1292 dprintf(" %p DUMMY PAGE state %d (%s)\n", page
, page
->state
, page_state_to_text(page
->state
));
1294 dprintf(" %p UNKNOWN PAGE type %d\n", page
, page
->type
);
1298 static void _dump_region(vm_region
*region
)
1300 dprintf("dump of region at %p:\n", region
);
1301 dprintf("magic: 0x%x ", region
->magic
);
1302 if(region
->magic
== VM_REGION_MAGIC
)
1303 dprintf("(GOOD)\n");
1305 dprintf("(BAD!)\n");
1306 dprintf("name: '%s'\n", region
->name
);
1307 dprintf("id: 0x%x\n", region
->id
);
1308 dprintf("base: 0x%lx\n", region
->base
);
1309 dprintf("size: 0x%lx\n", region
->size
);
1310 dprintf("lock: 0x%x\n", region
->lock
);
1311 dprintf("wiring: 0x%x\n", region
->wiring
);
1312 dprintf("ref_count: %d\n", region
->ref_count
);
1313 dprintf("cache_offset: 0x%Lx\n", region
->cache_offset
);
1314 dprintf("cache_ref: %p\n", region
->cache_ref
);
1315 dprintf("aspace: %p\n", region
->aspace
);
1316 dprintf("aspace_next: %p\n", region
->aspace_next
);
1317 dprintf("cache_next: %p\n", region
->cache_next
);
1318 dprintf("cache_prev: %p\n", region
->cache_prev
);
1319 dprintf("hash_next: %p\n", region
->hash_next
);
1322 static void dump_region(int argc
, char **argv
)
1327 dprintf("region: not enough arguments\n");
1331 // if the argument looks like a hex number, treat it as such
1332 if(strlen(argv
[1]) > 2 && argv
[1][0] == '0' && argv
[1][1] == 'x') {
1333 unsigned long num
= atoul(argv
[1]);
1336 region
= hash_lookup(region_table
, &id
);
1337 if(region
== NULL
) {
1338 dprintf("invalid region id\n");
1340 _dump_region(region
);
1344 // walk through the region list, looking for the arguments as a name
1345 struct hash_iterator iter
;
1347 hash_open(region_table
, &iter
);
1348 while((region
= hash_next(region_table
, &iter
)) != NULL
) {
1349 if(region
->name
!= NULL
&& strcmp(argv
[1], region
->name
) == 0) {
1350 _dump_region(region
);
1356 static void dump_region_list(int argc
, char **argv
)
1359 struct hash_iterator iter
;
1361 dprintf("addr\tid\t%32s\tbase\t\tsize\tlock\twiring\n", "name");
1363 hash_open(region_table
, &iter
);
1364 while((region
= hash_next(region_table
, &iter
)) != NULL
) {
1365 dprintf("%p\t0x%x\t%32s\t0x%lx\t\t0x%lx\t%d\t%d\n",
1366 region
, region
->id
, region
->name
, region
->base
, region
->size
, region
->lock
, region
->wiring
);
1368 hash_close(region_table
, &iter
, false);
1371 static void _dump_aspace(vm_address_space
*aspace
)
1375 dprintf("dump of address space at %p:\n", aspace
);
1376 dprintf("magic: 0x%x ", aspace
->magic
);
1377 if(aspace
->magic
== VM_ASPACE_MAGIC
)
1378 dprintf("(GOOD)\n");
1380 dprintf("(BAD!)\n");
1381 dprintf("name: '%s'\n", aspace
->name
);
1382 dprintf("id: 0x%x\n", aspace
->id
);
1383 dprintf("ref_count: %d\n", aspace
->ref_count
);
1384 dprintf("fault_count: %d\n", aspace
->fault_count
);
1385 dprintf("state: %d\n", aspace
->state
);
1386 dprintf("scan_va: 0x%lx\n", aspace
->scan_va
);
1387 dprintf("working_set_size: 0x%lx\n", aspace
->working_set_size
);
1388 dprintf("max_working_set: 0x%lx\n", aspace
->max_working_set
);
1389 dprintf("min_working_set: 0x%lx\n", aspace
->min_working_set
);
1390 dprintf("last_working_set_adjust: %Ld\n", aspace
->last_working_set_adjust
);
1391 dprintf("hash_next: %p\n", aspace
->hash_next
);
1392 dprintf("translation_map: %p\n", &aspace
->translation_map
);
1393 dprintf("virtual_map.base: 0x%lx\n", aspace
->virtual_map
.base
);
1394 dprintf("virtual_map.size: 0x%lx\n", aspace
->virtual_map
.size
);
1395 dprintf("virtual_map.change_count: 0x%x\n", aspace
->virtual_map
.change_count
);
1396 dprintf("virtual_map.sem: 0x%x\n", aspace
->virtual_map
.sem
);
1397 dprintf("virtual_map.region_hint: %p\n", aspace
->virtual_map
.region_hint
);
1398 dprintf("virtual_map.region_list:\n");
1399 for(region
= aspace
->virtual_map
.region_list
; region
!= NULL
; region
= region
->aspace_next
) {
1400 dprintf(" region 0x%x: ", region
->id
);
1401 dprintf("base_addr = 0x%lx ", region
->base
);
1402 dprintf("size = 0x%lx ", region
->size
);
1403 dprintf("name = '%s' ", region
->name
);
1404 dprintf("lock = 0x%x\n", region
->lock
);
1408 static void dump_aspace(int argc
, char **argv
)
1410 vm_address_space
*aspace
;
1413 dprintf("aspace: not enough arguments\n");
1417 // if the argument looks like a hex number, treat it as such
1418 if(strlen(argv
[1]) > 2 && argv
[1][0] == '0' && argv
[1][1] == 'x') {
1419 unsigned long num
= atoul(argv
[1]);
1422 aspace
= hash_lookup(aspace_table
, &id
);
1423 if(aspace
== NULL
) {
1424 dprintf("invalid aspace id\n");
1426 _dump_aspace(aspace
);
1430 // walk through the aspace list, looking for the arguments as a name
1431 struct hash_iterator iter
;
1433 hash_open(aspace_table
, &iter
);
1434 while((aspace
= hash_next(aspace_table
, &iter
)) != NULL
) {
1435 if(aspace
->name
!= NULL
&& strcmp(argv
[1], aspace
->name
) == 0) {
1436 _dump_aspace(aspace
);
1442 static void dump_aspace_list(int argc
, char **argv
)
1444 vm_address_space
*as
;
1445 struct hash_iterator iter
;
1447 dprintf("addr\tid\t%32s\tbase\t\tsize\n", "name");
1449 hash_open(aspace_table
, &iter
);
1450 while((as
= hash_next(aspace_table
, &iter
)) != NULL
) {
1451 dprintf("%p\t0x%x\t%32s\t0x%lx\t\t0x%lx\n",
1452 as
, as
->id
, as
->name
, as
->virtual_map
.base
, as
->virtual_map
.size
);
1454 hash_close(aspace_table
, &iter
, false);
1457 vm_address_space
*vm_get_kernel_aspace(void)
1459 VERIFY_VM_ASPACE(kernel_aspace
);
1461 /* we can treat this one a little differently since it can't be deleted */
1462 sem_acquire(aspace_hash_sem
, READ_COUNT
);
1463 atomic_add(&kernel_aspace
->ref_count
, 1);
1464 sem_release(aspace_hash_sem
, READ_COUNT
);
1465 return kernel_aspace
;
1468 aspace_id
vm_get_kernel_aspace_id(void)
1470 VERIFY_VM_ASPACE(kernel_aspace
);
1471 return kernel_aspace
->id
;
1474 vm_address_space
*vm_get_current_user_aspace(void)
1476 return vm_get_aspace_by_id(vm_get_current_user_aspace_id());
1479 aspace_id
vm_get_current_user_aspace_id(void)
1481 struct thread
*t
= thread_get_current_thread();
1484 return t
->proc
->aspace_id
;
1489 void vm_put_aspace(vm_address_space
*aspace
)
1491 bool removeit
= false;
1493 VERIFY_VM_ASPACE(aspace
);
1495 sem_acquire(aspace_hash_sem
, WRITE_COUNT
);
1496 if(atomic_add(&aspace
->ref_count
, -1) == 1) {
1497 hash_remove(aspace_table
, aspace
);
1500 sem_release(aspace_hash_sem
, WRITE_COUNT
);
1505 dprintf("vm_put_aspace: reached zero ref, deleting aspace\n");
1507 if(aspace
== kernel_aspace
)
1508 panic("vm_put_aspace: tried to delete the kernel aspace!\n");
1510 if(aspace
->state
!= VM_ASPACE_STATE_DELETION
)
1511 panic("vm_put_apsace: removed the last ref to aspace %p that's not in the DELETION state\n", aspace
);
1513 if(aspace
->virtual_map
.region_list
)
1514 panic("vm_put_aspace: aspace at %p has zero ref count, but region list isn't empty!\n", aspace
);
1516 (*aspace
->translation_map
.ops
->destroy
)(&aspace
->translation_map
);
1518 kfree(aspace
->name
);
1519 sem_delete(aspace
->virtual_map
.sem
);
1525 aspace_id
vm_create_aspace(const char *name
, addr_t base
, addr_t size
, bool kernel
)
1527 vm_address_space
*aspace
;
1530 aspace
= (vm_address_space
*)kmalloc(sizeof(vm_address_space
));
1531 if(aspace
== NULL
) {
1532 err
= ERR_NO_MEMORY
;
1536 aspace
->name
= (char *)kmalloc(strlen(name
) + 1);
1537 if(aspace
->name
== NULL
) {
1538 err
= ERR_NO_MEMORY
;
1541 strcpy(aspace
->name
, name
);
1543 aspace
->magic
= VM_ASPACE_MAGIC
;
1544 aspace
->id
= next_aspace_id
++;
1545 aspace
->ref_count
= 1;
1546 aspace
->state
= VM_ASPACE_STATE_NORMAL
;
1547 aspace
->fault_count
= 0;
1548 aspace
->scan_va
= base
;
1549 aspace
->working_set_size
= kernel
? DEFAULT_KERNEL_WORKING_SET
: DEFAULT_WORKING_SET
;
1550 aspace
->max_working_set
= DEFAULT_MAX_WORKING_SET
;
1551 aspace
->min_working_set
= DEFAULT_MIN_WORKING_SET
;
1552 aspace
->last_working_set_adjust
= system_time();
1554 // initialize the corresponding translation map
1555 err
= vm_translation_map_create(&aspace
->translation_map
, kernel
);
1559 // initialize the virtual map
1560 aspace
->virtual_map
.base
= base
;
1561 aspace
->virtual_map
.size
= size
;
1562 aspace
->virtual_map
.region_list
= NULL
;
1563 aspace
->virtual_map
.region_hint
= NULL
;
1564 aspace
->virtual_map
.change_count
= 0;
1565 aspace
->virtual_map
.sem
= sem_create(WRITE_COUNT
, "aspacelock");
1566 aspace
->virtual_map
.aspace
= aspace
;
1568 // add the aspace to the global hash table
1569 sem_acquire(aspace_hash_sem
, WRITE_COUNT
);
1570 hash_insert(aspace_table
, aspace
);
1571 sem_release(aspace_hash_sem
, WRITE_COUNT
);
1576 kfree(aspace
->name
);
1583 int vm_delete_aspace(aspace_id aid
)
1587 vm_address_space
*aspace
;
1589 aspace
= vm_get_aspace_by_id(aid
);
1591 return ERR_VM_INVALID_ASPACE
;
1593 dprintf("vm_delete_aspace: called on aspace 0x%x\n", aid
);
1595 // put this aspace in the deletion state
1596 // this guarantees that no one else will add regions to the list
1597 sem_acquire(aspace
->virtual_map
.sem
, WRITE_COUNT
);
1598 if(aspace
->state
== VM_ASPACE_STATE_DELETION
) {
1599 // abort, someone else is already deleting this aspace
1600 sem_release(aspace
->virtual_map
.sem
, WRITE_COUNT
);
1601 vm_put_aspace(aspace
);
1604 aspace
->state
= VM_ASPACE_STATE_DELETION
;
1606 // delete all the regions in this aspace
1607 region
= aspace
->virtual_map
.region_list
;
1609 VERIFY_VM_REGION(region
);
1610 next
= region
->aspace_next
;
1611 // decrement the ref on this region, may actually push the ref < 0, but that's okay
1612 _vm_put_region(region
, true);
1617 sem_release(aspace
->virtual_map
.sem
, WRITE_COUNT
);
1619 // release two refs on the address space
1620 vm_put_aspace(aspace
);
1621 vm_put_aspace(aspace
);
1626 int vm_aspace_walk_start(struct hash_iterator
*i
)
1628 hash_open(aspace_table
, i
);
1632 vm_address_space
*vm_aspace_walk_next(struct hash_iterator
*i
)
1634 vm_address_space
*aspace
;
1636 sem_acquire(aspace_hash_sem
, READ_COUNT
);
1637 aspace
= hash_next(aspace_table
, i
);
1639 VERIFY_VM_ASPACE(aspace
);
1640 atomic_add(&aspace
->ref_count
, 1);
1642 sem_release(aspace_hash_sem
, READ_COUNT
);
1646 static int vm_thread_dump_max_commit(void *unused
)
1653 thread_snooze(1000000);
1654 if(oldmax
!= max_commit
)
1655 dprintf("max_commit 0x%x\n", max_commit
);
1656 oldmax
= max_commit
;
1660 int vm_init(kernel_args
*ka
)
1668 dprintf("vm_init: entry\n");
1669 kprintf("initializing vm system...\n");
1671 err
= vm_translation_map_module_init(ka
);
1672 err
= arch_vm_init(ka
);
1674 // initialize some globals
1675 kernel_aspace
= NULL
;
1677 region_hash_sem
= -1;
1679 aspace_hash_sem
= -1;
1680 max_commit
= 0; // will be increased in vm_page_init
1681 max_commit_lock
= 0;
1682 memset(&vm_info
, 0, sizeof(vm_info
));
1684 // figure the size of memory
1687 // map in the new heap and initialize it
1688 heap_size
= ROUNDUP(vm_get_mem_size() / 32, 1*1024*1024);
1689 if(heap_size
> 16*1024*1024)
1690 heap_size
= 16*1024*1024;
1691 heap_base
= vm_alloc_from_ka_struct(ka
, heap_size
, LOCK_KERNEL
|LOCK_RW
);
1692 dprintf("heap at 0x%lx, size 0x%lx\n", heap_base
, heap_size
);
1693 kprintf("creating kernel heap at 0x%lx, size 0x%lx\n", heap_base
, heap_size
);
1694 heap_init(heap_base
, heap_size
);
1696 // initialize the free page list and page allocator
1697 vm_page_init_postheap(ka
);
1699 // initialize the hash table that stores the pages mapped to caches
1702 // create the region and address space hash tables
1704 vm_address_space
*aspace
;
1705 aspace_table
= hash_init(ASPACE_HASH_TABLE_SIZE
, (addr_t
)&aspace
->hash_next
- (addr_t
)aspace
,
1706 &aspace_compare
, &aspace_hash
);
1707 if(aspace_table
== NULL
)
1708 panic("vm_init: error creating aspace hash table\n");
1712 region_table
= hash_init(REGION_HASH_TABLE_SIZE
, (addr_t
)®ion
->hash_next
- (addr_t
)region
,
1713 ®ion_compare
, ®ion_hash
);
1714 if(region_table
== NULL
)
1715 panic("vm_init: error creating aspace hash table\n");
1719 // create the initial kernel address space
1722 aid
= vm_create_aspace("kernel_land", KERNEL_BASE
, KERNEL_SIZE
, true);
1724 panic("vm_init: error creating kernel address space!\n");
1725 kernel_aspace
= vm_get_aspace_by_id(aid
);
1726 vm_put_aspace(kernel_aspace
);
1729 // do any further initialization that the architecture dependant layers may need now
1730 vm_translation_map_module_init2(ka
);
1734 // allocate regions to represent stuff that already exists
1735 null_addr
= (void *)ROUNDOWN(heap_base
, PAGE_SIZE
);
1736 vm_create_anonymous_region(vm_get_kernel_aspace_id(), "kernel_heap", &null_addr
, REGION_ADDR_EXACT_ADDRESS
,
1737 heap_size
, REGION_WIRING_WIRED_ALREADY
, LOCK_RW
|LOCK_KERNEL
);
1739 null_addr
= (void *)ROUNDOWN(ka
->kernel_seg0_addr
.start
, PAGE_SIZE
);
1740 vm_create_anonymous_region(vm_get_kernel_aspace_id(), "kernel_seg0", &null_addr
, REGION_ADDR_EXACT_ADDRESS
,
1741 PAGE_ALIGN(ka
->kernel_seg0_addr
.size
), REGION_WIRING_WIRED_ALREADY
, LOCK_RW
|LOCK_KERNEL
);
1743 if(ka
->kernel_seg1_addr
.size
> 0) {
1744 null_addr
= (void *)ROUNDOWN(ka
->kernel_seg1_addr
.start
, PAGE_SIZE
);
1745 vm_create_anonymous_region(vm_get_kernel_aspace_id(), "kernel_seg1", &null_addr
, REGION_ADDR_EXACT_ADDRESS
,
1746 PAGE_ALIGN(ka
->kernel_seg1_addr
.size
), REGION_WIRING_WIRED_ALREADY
, LOCK_RW
|LOCK_KERNEL
);
1748 for(i
=0; i
< ka
->num_cpus
; i
++) {
1751 sprintf(temp
, "idle_thread%d_kstack", i
);
1752 null_addr
= (void *)ka
->cpu_kstack
[i
].start
;
1753 vm_create_anonymous_region(vm_get_kernel_aspace_id(), temp
, &null_addr
, REGION_ADDR_EXACT_ADDRESS
,
1754 ka
->cpu_kstack
[i
].size
, REGION_WIRING_WIRED_ALREADY
, LOCK_RW
|LOCK_KERNEL
);
1757 arch_vm_init_existing_maps(ka
);
1759 // map in the boot dir
1762 vm_map_physical_memory(vm_get_kernel_aspace_id(), "bootdir", &null
, REGION_ADDR_ANY_ADDRESS
,
1763 ka
->bootdir_addr
.size
, LOCK_RO
|LOCK_KERNEL
, ka
->bootdir_addr
.start
);
1766 arch_vm_init_endvm(ka
);
1768 // add some debugger commands
1769 dbg_add_command(&dump_region_list
, "regions", "Dump a list of all regions");
1770 dbg_add_command(&dump_region
, "region", "Dump info about a particular region");
1771 dbg_add_command(&dump_aspace_list
, "aspaces", "Dump a list of all address spaces");
1772 dbg_add_command(&dump_aspace
, "aspace", "Dump info about a particular address space");
1773 dbg_add_command(&dump_cache_ref
, "cache_ref", "Dump cache_ref data structure");
1774 dbg_add_command(&dump_cache
, "cache", "Dump cache_ref data structure");
1775 // dbg_add_command(&display_mem, "dl", "dump memory long words (64-bit)");
1776 dbg_add_command(&display_mem
, "dw", "dump memory words (32-bit)");
1777 dbg_add_command(&display_mem
, "ds", "dump memory shorts (16-bit)");
1778 dbg_add_command(&display_mem
, "db", "dump memory bytes (8-bit)");
1780 dprintf("vm_init: exit\n");
1785 int vm_init_postsem(kernel_args
*ka
)
1789 // fill in all of the semaphores that were not allocated before
1790 // since we're still single threaded and only the kernel address space exists,
1791 // it isn't that hard to find all of the ones we need to create
1792 vm_translation_map_module_init_post_sem(ka
);
1793 kernel_aspace
->virtual_map
.sem
= sem_create(WRITE_COUNT
, "kernel_aspacelock");
1794 recursive_lock_create(&kernel_aspace
->translation_map
.lock
);
1796 for(region
= kernel_aspace
->virtual_map
.region_list
; region
; region
= region
->aspace_next
) {
1797 if(region
->cache_ref
->lock
.sem
< 0) {
1798 mutex_init(®ion
->cache_ref
->lock
, "cache_ref_mutex");
1802 region_hash_sem
= sem_create(WRITE_COUNT
, "region_hash_sem");
1803 aspace_hash_sem
= sem_create(WRITE_COUNT
, "aspace_hash_sem");
1805 return heap_init_postsem(ka
);
1808 int vm_init_postthread(kernel_args
*ka
)
1810 vm_page_init_postthread(ka
);
1813 thread_id tid
= thread_create_kernel_thread("max_commit_thread", &vm_thread_dump_max_commit
, NULL
);
1814 thread_resume_thread(tid
);
1822 int vm_page_fault(addr_t address
, addr_t fault_address
, bool is_write
, bool is_user
, addr_t
*newip
)
1826 // dprintf("vm_page_fault: page fault at 0x%x, ip 0x%x\n", address, fault_address);
1830 err
= vm_soft_fault(address
, is_write
, is_user
);
1832 dprintf("vm_page_fault: vm_soft_fault returned error %d on fault at 0x%lx, ip 0x%lx, write %d, user %d, thread 0x%x\n",
1833 err
, address
, fault_address
, is_write
, is_user
, thread_get_current_thread_id());
1835 struct thread
*t
= thread_get_current_thread();
1836 if(t
&& t
->fault_handler
!= 0) {
1837 // this will cause the arch dependant page fault handler to
1838 // modify the IP on the interrupt frame or whatever to return
1840 *newip
= t
->fault_handler
;
1842 // unhandled page fault in the kernel
1843 panic("vm_page_fault: unhandled page fault in kernel space at 0x%lx, ip 0x%lx\n",
1844 address
, fault_address
);
1847 dprintf("vm_page_fault: killing process 0x%x\n", thread_get_current_thread()->proc
->id
);
1848 proc_kill_proc(thread_get_current_thread()->proc
->id
);
1852 return INT_NO_RESCHEDULE
;
1855 #define TRACE_PFAULT 0
1858 #define TRACE dprintf("in pfault at line %d\n", __LINE__)
1863 static int vm_soft_fault(addr_t address
, bool is_write
, bool is_user
)
1865 vm_address_space
*aspace
;
1866 vm_virtual_map
*map
;
1868 vm_cache_ref
*cache_ref
;
1869 vm_cache_ref
*last_cache_ref
;
1870 vm_cache_ref
*top_cache_ref
;
1873 vm_page
*page
= NULL
;
1877 // dprintf("vm_soft_fault: thid 0x%x address 0x%x, is_write %d, is_user %d\n",
1878 // thread_get_current_thread_id(), address, is_write, is_user);
1880 atomic_add(&vm_info
.page_faults
, 1);
1882 address
= ROUNDOWN(address
, PAGE_SIZE
);
1884 if(address
>= KERNEL_BASE
&& address
<= KERNEL_TOP
) {
1885 aspace
= vm_get_kernel_aspace();
1886 } else if(address
>= USER_BASE
&& address
<= USER_TOP
) {
1887 aspace
= vm_get_current_user_aspace();
1888 if(aspace
== NULL
) {
1889 if(is_user
== false) {
1890 dprintf("vm_soft_fault: kernel thread accessing invalid user memory!\n");
1891 return ERR_VM_PF_FATAL
;
1894 panic("vm_soft_fault: non kernel thread accessing user memory that doesn't exist!\n");
1898 // the hit was probably in the 64k DMZ between kernel and user space
1899 // this keeps a user space thread from passing a buffer that crosses into kernel space
1900 return ERR_VM_PF_FATAL
;
1902 map
= &aspace
->virtual_map
;
1903 atomic_add(&aspace
->fault_count
, 1);
1905 sem_acquire(map
->sem
, READ_COUNT
);
1906 region
= vm_virtual_map_lookup(map
, address
);
1907 if(region
== NULL
) {
1908 sem_release(map
->sem
, READ_COUNT
);
1909 vm_put_aspace(aspace
);
1910 dprintf("vm_soft_fault: va 0x%lx not covered by region in address space\n", address
);
1911 return ERR_VM_PF_BAD_ADDRESS
; // BAD_ADDRESS
1914 // check permissions
1915 if(is_user
&& (region
->lock
& LOCK_KERNEL
) == LOCK_KERNEL
) {
1916 sem_release(map
->sem
, READ_COUNT
);
1917 vm_put_aspace(aspace
);
1918 dprintf("user access on kernel region\n");
1919 return ERR_VM_PF_BAD_PERM
; // BAD_PERMISSION
1921 if(is_write
&& (region
->lock
& LOCK_RW
) == 0) {
1922 sem_release(map
->sem
, READ_COUNT
);
1923 vm_put_aspace(aspace
);
1924 dprintf("write access attempted on read-only region\n");
1925 return ERR_VM_PF_BAD_PERM
; // BAD_PERMISSION
1930 top_cache_ref
= region
->cache_ref
;
1931 VERIFY_VM_CACHE_REF(top_cache_ref
);
1932 cache_offset
= address
- region
->base
+ region
->cache_offset
;
1933 vm_cache_acquire_ref(top_cache_ref
, true);
1934 change_count
= map
->change_count
;
1935 sem_release(map
->sem
, READ_COUNT
);
1937 VERIFY_VM_CACHE(top_cache_ref
->cache
);
1938 VERIFY_VM_STORE(top_cache_ref
->cache
->store
);
1940 // see if this cache has a fault handler
1941 if(top_cache_ref
->cache
->store
->ops
->fault
) {
1942 int err
= (*top_cache_ref
->cache
->store
->ops
->fault
)(top_cache_ref
->cache
->store
, aspace
, cache_offset
);
1943 vm_cache_release_ref(top_cache_ref
);
1944 vm_put_aspace(aspace
);
1950 dummy_page
.magic
= VM_PAGE_MAGIC
;
1951 dummy_page
.state
= PAGE_STATE_INACTIVE
;
1952 dummy_page
.type
= PAGE_TYPE_DUMMY
;
1954 last_cache_ref
= top_cache_ref
;
1955 for(cache_ref
= top_cache_ref
; cache_ref
; cache_ref
= (cache_ref
->cache
->source
) ? cache_ref
->cache
->source
->ref
: NULL
) {
1956 VERIFY_VM_CACHE_REF(cache_ref
);
1957 mutex_lock(&cache_ref
->lock
);
1962 page
= vm_cache_lookup_page(cache_ref
, cache_offset
);
1963 if(page
!= NULL
&& page
->state
!= PAGE_STATE_BUSY
) {
1964 vm_page_set_state(page
, PAGE_STATE_BUSY
);
1965 mutex_unlock(&cache_ref
->lock
);
1974 // page must be busy
1975 mutex_unlock(&cache_ref
->lock
);
1976 thread_snooze(20000);
1977 mutex_lock(&cache_ref
->lock
);
1987 // insert this dummy page here to keep other threads from faulting on the
1988 // same address and chasing us up the cache chain
1989 if(cache_ref
== top_cache_ref
) {
1990 dummy_page
.state
= PAGE_STATE_BUSY
;
1991 vm_cache_insert_page(cache_ref
, &dummy_page
, cache_offset
);
1994 VERIFY_VM_CACHE(cache_ref
->cache
);
1995 VERIFY_VM_STORE(cache_ref
->cache
->store
);
1997 // see if the vm_store has it
1998 if(cache_ref
->cache
->store
->ops
->has_page
) {
1999 if(cache_ref
->cache
->store
->ops
->has_page(cache_ref
->cache
->store
, cache_offset
)) {
2004 mutex_unlock(&cache_ref
->lock
);
2007 vecs
->total_len
= PAGE_SIZE
;
2008 vecs
->vec
[0].len
= PAGE_SIZE
;
2010 page
= vm_page_allocate_page(PAGE_STATE_FREE
);
2011 (*aspace
->translation_map
.ops
->get_physical_page
)(page
->ppn
* PAGE_SIZE
, (addr_t
*)&vecs
->vec
[0].start
, PHYSICAL_PAGE_CAN_WAIT
);
2012 // handle errors here
2013 err
= cache_ref
->cache
->store
->ops
->read(cache_ref
->cache
->store
, cache_offset
, vecs
);
2014 (*aspace
->translation_map
.ops
->put_physical_page
)((addr_t
)vecs
->vec
[0].start
);
2016 mutex_lock(&cache_ref
->lock
);
2018 if(cache_ref
== top_cache_ref
) {
2019 vm_cache_remove_page(cache_ref
, &dummy_page
);
2020 dummy_page
.state
= PAGE_STATE_INACTIVE
;
2022 vm_cache_insert_page(cache_ref
, page
, cache_offset
);
2023 mutex_unlock(&cache_ref
->lock
);
2027 mutex_unlock(&cache_ref
->lock
);
2028 last_cache_ref
= cache_ref
;
2034 // we rolled off the end of the cache chain, so we need to decide which
2035 // cache will get the new page we're about to create
2038 cache_ref
= last_cache_ref
; // put it in the deepest cache
2040 cache_ref
= top_cache_ref
; // put it in the topmost cache
2046 // still haven't found a page, so zero out a new one
2047 page
= vm_page_allocate_page(PAGE_STATE_CLEAR
);
2048 // dprintf("vm_soft_fault: just allocated page 0x%x\n", page->ppn);
2049 mutex_lock(&cache_ref
->lock
);
2050 if(dummy_page
.state
== PAGE_STATE_BUSY
&& dummy_page
.cache_ref
== cache_ref
) {
2051 vm_cache_remove_page(cache_ref
, &dummy_page
);
2052 dummy_page
.state
= PAGE_STATE_INACTIVE
;
2054 vm_cache_insert_page(cache_ref
, page
, cache_offset
);
2055 mutex_unlock(&cache_ref
->lock
);
2056 if(dummy_page
.state
== PAGE_STATE_BUSY
) {
2057 vm_cache_ref
*temp_cache
= dummy_page
.cache_ref
;
2058 mutex_lock(&temp_cache
->lock
);
2059 vm_cache_remove_page(temp_cache
, &dummy_page
);
2060 mutex_unlock(&temp_cache
->lock
);
2061 dummy_page
.state
= PAGE_STATE_INACTIVE
;
2067 if(page
->cache_ref
!= top_cache_ref
&& is_write
) {
2068 // now we have a page that has the data we want, but in the wrong cache object
2069 // so we need to copy it and stick it into the top cache
2070 vm_page
*src_page
= page
;
2073 page
= vm_page_allocate_page(PAGE_STATE_FREE
);
2075 // try to get a mapping for the src and dest page so we can copy it
2077 (*aspace
->translation_map
.ops
->get_physical_page
)(src_page
->ppn
* PAGE_SIZE
, (addr_t
*)&src
, PHYSICAL_PAGE_CAN_WAIT
);
2078 err
= (*aspace
->translation_map
.ops
->get_physical_page
)(page
->ppn
* PAGE_SIZE
, (addr_t
*)&dest
, PHYSICAL_PAGE_NO_WAIT
);
2082 // it couldn't map the second one, so sleep and retry
2083 // keeps an extremely rare deadlock from occuring
2084 (*aspace
->translation_map
.ops
->put_physical_page
)((addr_t
)src
);
2085 thread_snooze(5000);
2088 memcpy(dest
, src
, PAGE_SIZE
);
2089 (*aspace
->translation_map
.ops
->put_physical_page
)((addr_t
)src
);
2090 (*aspace
->translation_map
.ops
->put_physical_page
)((addr_t
)dest
);
2092 vm_page_set_state(src_page
, PAGE_STATE_ACTIVE
);
2094 mutex_lock(&top_cache_ref
->lock
);
2095 if(dummy_page
.state
== PAGE_STATE_BUSY
&& dummy_page
.cache_ref
== top_cache_ref
) {
2096 vm_cache_remove_page(top_cache_ref
, &dummy_page
);
2097 dummy_page
.state
= PAGE_STATE_INACTIVE
;
2099 vm_cache_insert_page(top_cache_ref
, page
, cache_offset
);
2100 mutex_unlock(&top_cache_ref
->lock
);
2102 if(dummy_page
.state
== PAGE_STATE_BUSY
) {
2103 vm_cache_ref
*temp_cache
= dummy_page
.cache_ref
;
2104 mutex_lock(&temp_cache
->lock
);
2105 vm_cache_remove_page(temp_cache
, &dummy_page
);
2106 mutex_unlock(&temp_cache
->lock
);
2107 dummy_page
.state
= PAGE_STATE_INACTIVE
;
2114 sem_acquire(map
->sem
, READ_COUNT
);
2115 if(change_count
!= map
->change_count
) {
2116 // something may have changed, see if the address is still valid
2117 region
= vm_virtual_map_lookup(map
, address
);
2119 || region
->cache_ref
!= top_cache_ref
2120 || (address
- region
->base
+ region
->cache_offset
) != cache_offset
) {
2121 dprintf("vm_soft_fault: address space layout changed effecting ongoing soft fault\n");
2122 err
= ERR_VM_PF_BAD_ADDRESS
; // BAD_ADDRESS
2129 int new_lock
= region
->lock
;
2130 if(page
->cache_ref
!= top_cache_ref
&& !is_write
)
2131 new_lock
&= ~LOCK_RW
;
2133 atomic_add(&page
->ref_count
, 1);
2134 (*aspace
->translation_map
.ops
->lock
)(&aspace
->translation_map
);
2135 (*aspace
->translation_map
.ops
->map
)(&aspace
->translation_map
, address
,
2136 page
->ppn
* PAGE_SIZE
, new_lock
);
2137 (*aspace
->translation_map
.ops
->unlock
)(&aspace
->translation_map
);
2142 sem_release(map
->sem
, READ_COUNT
);
2146 if(dummy_page
.state
== PAGE_STATE_BUSY
) {
2147 vm_cache_ref
*temp_cache
= dummy_page
.cache_ref
;
2148 mutex_lock(&temp_cache
->lock
);
2149 vm_cache_remove_page(temp_cache
, &dummy_page
);
2150 mutex_unlock(&temp_cache
->lock
);
2151 dummy_page
.state
= PAGE_STATE_INACTIVE
;
2156 vm_page_set_state(page
, PAGE_STATE_ACTIVE
);
2158 vm_cache_release_ref(top_cache_ref
);
2159 vm_put_aspace(aspace
);
2166 static vm_region
*vm_virtual_map_lookup(vm_virtual_map
*map
, addr_t address
)
2170 // check the region_hint region first
2171 region
= map
->region_hint
;
2173 VERIFY_VM_REGION(region
);
2174 if(region
&& region
->base
<= address
&& (region
->base
+ region
->size
) > address
)
2177 for(region
= map
->region_list
; region
!= NULL
; region
= region
->aspace_next
) {
2178 VERIFY_VM_REGION(region
);
2179 if(region
->base
<= address
&& (region
->base
+ region
->size
) > address
)
2184 map
->region_hint
= region
;
2185 VERIFY_VM_REGION(region
);
2190 int vm_get_physical_page(addr_t paddr
, addr_t
*vaddr
, int flags
)
2193 VERIFY_VM_ASPACE(kernel_aspace
);
2195 return (*kernel_aspace
->translation_map
.ops
->get_physical_page
)(paddr
, vaddr
, flags
);
2198 int vm_put_physical_page(addr_t vaddr
)
2201 VERIFY_VM_ASPACE(kernel_aspace
);
2203 return (*kernel_aspace
->translation_map
.ops
->put_physical_page
)(vaddr
);
2206 void vm_increase_max_commit(addr_t delta
)
2208 // dprintf("vm_increase_max_commit: delta 0x%x\n", delta);
2210 int_disable_interrupts();
2211 acquire_spinlock(&max_commit_lock
);
2212 max_commit
+= delta
;
2213 vm_info
.committed_mem
+= delta
;
2214 release_spinlock(&max_commit_lock
);
2215 int_restore_interrupts();
2218 int user_memcpy(void *to
, const void *from
, size_t size
)
2220 return arch_cpu_user_memcpy(to
, from
, size
, &thread_get_current_thread()->fault_handler
);
2223 int user_strcpy(char *to
, const char *from
)
2225 return arch_cpu_user_strcpy(to
, from
, &thread_get_current_thread()->fault_handler
);
2228 int user_strncpy(char *to
, const char *from
, size_t size
)
2230 return arch_cpu_user_strncpy(to
, from
, size
, &thread_get_current_thread()->fault_handler
);
2233 int user_memset(void *s
, char c
, size_t count
)
2235 return arch_cpu_user_memset(s
, c
, count
, &thread_get_current_thread()->fault_handler
);
2238 addr_t
vm_get_mem_size(void)
2240 return vm_info
.physical_page_size
* vm_info
.physical_pages
;