Moved everything from vm.c belonging to vm_address_space into a separate file.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9253 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
90c2fee933
commit
894e120a01
@ -2,6 +2,7 @@ SubDir OBOS_TOP src kernel core vm ;
|
||||
|
||||
KernelMergeObject kernel_vm.o :
|
||||
vm.c
|
||||
vm_address_space.c
|
||||
vm_cache.c
|
||||
vm_daemons.c
|
||||
vm_page.c
|
||||
@ -10,5 +11,5 @@ KernelMergeObject kernel_vm.o :
|
||||
vm_store_null.c
|
||||
vm_tests.c
|
||||
|
||||
: -fno-pic -Wno-unused -D_KERNEL_MODE=1
|
||||
: -fno-pic -Wno-unused
|
||||
;
|
||||
|
@ -57,18 +57,13 @@
|
||||
#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1))
|
||||
#define ROUNDOWN(a, b) (((a) / (b)) * (b))
|
||||
|
||||
static vm_address_space *kernel_aspace;
|
||||
extern vm_address_space *kernel_aspace;
|
||||
|
||||
#define REGION_HASH_TABLE_SIZE 1024
|
||||
static region_id next_region_id;
|
||||
static void *region_table;
|
||||
static sem_id region_hash_sem;
|
||||
|
||||
#define ASPACE_HASH_TABLE_SIZE 1024
|
||||
static aspace_id next_aspace_id;
|
||||
static void *aspace_table;
|
||||
static sem_id aspace_hash_sem;
|
||||
|
||||
static int max_commit;
|
||||
static spinlock max_commit_lock;
|
||||
|
||||
@ -109,47 +104,6 @@ region_hash(void *_r, const void *key, uint32 range)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
aspace_compare(void *_a, const void *key)
|
||||
{
|
||||
vm_address_space *aspace = _a;
|
||||
const aspace_id *id = key;
|
||||
|
||||
if (aspace->id == *id)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static uint32
|
||||
aspace_hash(void *_a, const void *key, uint32 range)
|
||||
{
|
||||
vm_address_space *aspace = _a;
|
||||
const aspace_id *id = key;
|
||||
|
||||
if(aspace != NULL)
|
||||
return (aspace->id % range);
|
||||
else
|
||||
return (*id % range);
|
||||
}
|
||||
|
||||
|
||||
vm_address_space *
|
||||
vm_get_aspace_by_id(aspace_id aid)
|
||||
{
|
||||
vm_address_space *aspace;
|
||||
|
||||
acquire_sem_etc(aspace_hash_sem, READ_COUNT, 0, 0);
|
||||
aspace = hash_lookup(aspace_table, &aid);
|
||||
if (aspace)
|
||||
atomic_add(&aspace->ref_count, 1);
|
||||
release_sem_etc(aspace_hash_sem, READ_COUNT, 0);
|
||||
|
||||
return aspace;
|
||||
}
|
||||
|
||||
|
||||
vm_region *
|
||||
vm_get_region_by_id(region_id rid)
|
||||
{
|
||||
@ -1616,217 +1570,6 @@ dump_region_list(int argc, char **argv)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_dump_aspace(vm_address_space *aspace)
|
||||
{
|
||||
vm_region *region;
|
||||
|
||||
dprintf("dump of address space at %p:\n", aspace);
|
||||
dprintf("name: '%s'\n", aspace->name);
|
||||
dprintf("id: 0x%lx\n", aspace->id);
|
||||
dprintf("ref_count: %ld\n", aspace->ref_count);
|
||||
dprintf("fault_count: %ld\n", aspace->fault_count);
|
||||
dprintf("working_set_size: 0x%lx\n", aspace->working_set_size);
|
||||
dprintf("translation_map: %p\n", &aspace->translation_map);
|
||||
dprintf("virtual_map.base: 0x%lx\n", aspace->virtual_map.base);
|
||||
dprintf("virtual_map.size: 0x%lx\n", aspace->virtual_map.size);
|
||||
dprintf("virtual_map.change_count: 0x%x\n", aspace->virtual_map.change_count);
|
||||
dprintf("virtual_map.sem: 0x%lx\n", aspace->virtual_map.sem);
|
||||
dprintf("virtual_map.region_hint: %p\n", aspace->virtual_map.region_hint);
|
||||
dprintf("virtual_map.region_list:\n");
|
||||
for (region = aspace->virtual_map.region_list; region != NULL; region = region->aspace_next) {
|
||||
dprintf(" region 0x%lx: ", region->id);
|
||||
dprintf("base_addr = 0x%lx ", region->base);
|
||||
dprintf("size = 0x%lx ", region->size);
|
||||
dprintf("name = '%s' ", region->name);
|
||||
dprintf("lock = 0x%x\n", region->lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_aspace(int argc, char **argv)
|
||||
{
|
||||
// int i;
|
||||
vm_address_space *aspace;
|
||||
|
||||
if (argc < 2) {
|
||||
dprintf("aspace: not enough arguments\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if the argument looks like a hex number, treat it as such
|
||||
if (strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') {
|
||||
unsigned long num = atoul(argv[1]);
|
||||
aspace_id id = num;
|
||||
|
||||
aspace = hash_lookup(aspace_table, &id);
|
||||
if (aspace == NULL) {
|
||||
dprintf("invalid aspace id\n");
|
||||
} else {
|
||||
_dump_aspace(aspace);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
// walk through the aspace list, looking for the arguments as a name
|
||||
struct hash_iterator iter;
|
||||
|
||||
hash_open(aspace_table, &iter);
|
||||
while ((aspace = hash_next(aspace_table, &iter)) != NULL) {
|
||||
if(aspace->name != NULL && strcmp(argv[1], aspace->name) == 0) {
|
||||
_dump_aspace(aspace);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_aspace_list(int argc, char **argv)
|
||||
{
|
||||
vm_address_space *as;
|
||||
struct hash_iterator iter;
|
||||
|
||||
dprintf("addr\tid\t%32s\tbase\t\tsize\n", "name");
|
||||
|
||||
hash_open(aspace_table, &iter);
|
||||
while ((as = hash_next(aspace_table, &iter)) != NULL) {
|
||||
dprintf("%p\t0x%lx\t%32s\t0x%lx\t\t0x%lx\n",
|
||||
as, as->id, as->name, as->virtual_map.base, as->virtual_map.size);
|
||||
}
|
||||
hash_close(aspace_table, &iter, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
vm_address_space *
|
||||
vm_get_kernel_aspace(void)
|
||||
{
|
||||
/* we can treat this one a little differently since it can't be deleted */
|
||||
acquire_sem_etc(aspace_hash_sem, READ_COUNT, 0, 0);
|
||||
atomic_add(&kernel_aspace->ref_count, 1);
|
||||
release_sem_etc(aspace_hash_sem, READ_COUNT, 0);
|
||||
return kernel_aspace;
|
||||
}
|
||||
|
||||
|
||||
aspace_id
|
||||
vm_get_kernel_aspace_id(void)
|
||||
{
|
||||
return kernel_aspace->id;
|
||||
}
|
||||
|
||||
|
||||
vm_address_space *
|
||||
vm_get_current_user_aspace(void)
|
||||
{
|
||||
return vm_get_aspace_by_id(vm_get_current_user_aspace_id());
|
||||
}
|
||||
|
||||
|
||||
aspace_id
|
||||
vm_get_current_user_aspace_id(void)
|
||||
{
|
||||
struct thread *t = thread_get_current_thread();
|
||||
|
||||
if (t)
|
||||
return t->team->_aspace_id;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
vm_put_aspace(vm_address_space *aspace)
|
||||
{
|
||||
// vm_region *region;
|
||||
bool removeit = false;
|
||||
|
||||
acquire_sem_etc(aspace_hash_sem, WRITE_COUNT, 0, 0);
|
||||
if (atomic_add(&aspace->ref_count, -1) == 1) {
|
||||
hash_remove(aspace_table, aspace);
|
||||
removeit = true;
|
||||
}
|
||||
release_sem_etc(aspace_hash_sem, WRITE_COUNT, 0);
|
||||
|
||||
if (!removeit)
|
||||
return;
|
||||
|
||||
TRACE(("vm_put_aspace: reached zero ref, deleting aspace\n"));
|
||||
|
||||
if (aspace == kernel_aspace)
|
||||
panic("vm_put_aspace: tried to delete the kernel aspace!\n");
|
||||
|
||||
if (aspace->virtual_map.region_list)
|
||||
panic("vm_put_aspace: aspace at %p has zero ref count, but region list isn't empty!\n", aspace);
|
||||
|
||||
(*aspace->translation_map.ops->destroy)(&aspace->translation_map);
|
||||
|
||||
free(aspace->name);
|
||||
delete_sem(aspace->virtual_map.sem);
|
||||
free(aspace);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
aspace_id
|
||||
vm_create_aspace(const char *name, addr_t base, addr_t size, bool kernel)
|
||||
{
|
||||
vm_address_space *aspace;
|
||||
int err;
|
||||
|
||||
|
||||
aspace = (vm_address_space *)malloc(sizeof(vm_address_space));
|
||||
if (aspace == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
TRACE(("vm_create_aspace: %s: %lx bytes starting at 0x%lx => %p\n", name, size, base, aspace));
|
||||
|
||||
aspace->name = (char *)malloc(strlen(name) + 1);
|
||||
if (aspace->name == NULL ) {
|
||||
free(aspace);
|
||||
return ENOMEM;
|
||||
}
|
||||
strcpy(aspace->name, name);
|
||||
|
||||
aspace->id = next_aspace_id++;
|
||||
aspace->ref_count = 1;
|
||||
aspace->state = VM_ASPACE_STATE_NORMAL;
|
||||
aspace->fault_count = 0;
|
||||
aspace->scan_va = base;
|
||||
aspace->working_set_size = kernel ? DEFAULT_KERNEL_WORKING_SET : DEFAULT_WORKING_SET;
|
||||
aspace->max_working_set = DEFAULT_MAX_WORKING_SET;
|
||||
aspace->min_working_set = DEFAULT_MIN_WORKING_SET;
|
||||
aspace->last_working_set_adjust = system_time();
|
||||
|
||||
// initialize the corresponding translation map
|
||||
err = vm_translation_map_create(&aspace->translation_map, kernel);
|
||||
if (err < 0) {
|
||||
free(aspace->name);
|
||||
free(aspace);
|
||||
return err;
|
||||
}
|
||||
|
||||
// initialize the virtual map
|
||||
aspace->virtual_map.base = base;
|
||||
aspace->virtual_map.size = size;
|
||||
aspace->virtual_map.region_list = NULL;
|
||||
aspace->virtual_map.region_hint = NULL;
|
||||
aspace->virtual_map.change_count = 0;
|
||||
aspace->virtual_map.sem = create_sem(WRITE_COUNT, "aspacelock");
|
||||
aspace->virtual_map.aspace = aspace;
|
||||
|
||||
// add the aspace to the global hash table
|
||||
acquire_sem_etc(aspace_hash_sem, WRITE_COUNT, 0, 0);
|
||||
hash_insert(aspace_table, aspace);
|
||||
release_sem_etc(aspace_hash_sem, WRITE_COUNT, 0);
|
||||
|
||||
return aspace->id;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
vm_delete_areas(struct vm_address_space *aspace)
|
||||
{
|
||||
@ -1854,41 +1597,6 @@ vm_delete_areas(struct vm_address_space *aspace)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
vm_delete_aspace(aspace_id aid)
|
||||
{
|
||||
vm_address_space *aspace;
|
||||
|
||||
aspace = vm_get_aspace_by_id(aid);
|
||||
if (aspace == NULL)
|
||||
return ERR_VM_INVALID_ASPACE;
|
||||
|
||||
TRACE(("vm_delete_aspace: called on aspace 0x%lx\n", aid));
|
||||
|
||||
// put this aspace in the deletion state
|
||||
// this guarantees that no one else will add regions to the list
|
||||
acquire_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0, 0);
|
||||
if (aspace->state == VM_ASPACE_STATE_DELETION) {
|
||||
// abort, someone else is already deleting this aspace
|
||||
release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0);
|
||||
vm_put_aspace(aspace);
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
aspace->state = VM_ASPACE_STATE_DELETION;
|
||||
|
||||
vm_delete_areas(aspace);
|
||||
|
||||
// unlock
|
||||
release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0);
|
||||
|
||||
// release two refs on the address space
|
||||
vm_put_aspace(aspace);
|
||||
vm_put_aspace(aspace);
|
||||
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
vm_resize_region(aspace_id aid, region_id rid, size_t newSize)
|
||||
{
|
||||
@ -1931,28 +1639,6 @@ vm_resize_region(aspace_id aid, region_id rid, size_t newSize)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
vm_aspace_walk_start(struct hash_iterator *i)
|
||||
{
|
||||
hash_open(aspace_table, i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
vm_address_space *
|
||||
vm_aspace_walk_next(struct hash_iterator *i)
|
||||
{
|
||||
vm_address_space *aspace;
|
||||
|
||||
acquire_sem_etc(aspace_hash_sem, READ_COUNT, 0, 0);
|
||||
aspace = hash_next(aspace_table, i);
|
||||
if (aspace)
|
||||
atomic_add(&aspace->ref_count, 1);
|
||||
release_sem_etc(aspace_hash_sem, READ_COUNT, 0);
|
||||
return aspace;
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
vm_thread_dump_max_commit(void *unused)
|
||||
{
|
||||
@ -2015,11 +1701,8 @@ vm_init(kernel_args *ka)
|
||||
err = arch_vm_init(ka);
|
||||
|
||||
// initialize some globals
|
||||
kernel_aspace = NULL;
|
||||
next_region_id = 0;
|
||||
region_hash_sem = -1;
|
||||
next_aspace_id = 0;
|
||||
aspace_hash_sem = -1;
|
||||
max_commit = 0; // will be increased in vm_page_init
|
||||
max_commit_lock = 0;
|
||||
|
||||
@ -2034,14 +1717,6 @@ vm_init(kernel_args *ka)
|
||||
// initialize the hash table that stores the pages mapped to caches
|
||||
vm_cache_init(ka);
|
||||
|
||||
// create the region and address space hash tables
|
||||
{
|
||||
vm_address_space *aspace;
|
||||
aspace_table = hash_init(ASPACE_HASH_TABLE_SIZE, (addr_t)&aspace->hash_next - (addr_t)aspace,
|
||||
&aspace_compare, &aspace_hash);
|
||||
if (aspace_table == NULL)
|
||||
panic("vm_init: error creating aspace hash table\n");
|
||||
}
|
||||
{
|
||||
vm_region *region;
|
||||
region_table = hash_init(REGION_HASH_TABLE_SIZE, (addr_t)®ion->hash_next - (addr_t)region,
|
||||
@ -2050,16 +1725,7 @@ vm_init(kernel_args *ka)
|
||||
panic("vm_init: error creating aspace hash table\n");
|
||||
}
|
||||
|
||||
|
||||
// create the initial kernel address space
|
||||
{
|
||||
aspace_id aid;
|
||||
aid = vm_create_aspace("kernel_land", KERNEL_BASE, KERNEL_SIZE, true);
|
||||
if (aid < 0)
|
||||
panic("vm_init: error creating kernel address space!\n");
|
||||
kernel_aspace = vm_get_aspace_by_id(aid);
|
||||
vm_put_aspace(kernel_aspace);
|
||||
}
|
||||
vm_aspace_init();
|
||||
|
||||
// do any further initialization that the architecture dependant layers may need now
|
||||
vm_translation_map_module_init2(ka);
|
||||
@ -2101,8 +1767,6 @@ vm_init(kernel_args *ka)
|
||||
// add some debugger commands
|
||||
add_debugger_command("regions", &dump_region_list, "Dump a list of all regions");
|
||||
add_debugger_command("region", &dump_region, "Dump info about a particular region");
|
||||
add_debugger_command("aspaces", &dump_aspace_list, "Dump a list of all address spaces");
|
||||
add_debugger_command("aspace", &dump_aspace, "Dump info about a particular address space");
|
||||
add_debugger_command("cache_ref", &dump_cache_ref, "Dump cache_ref data structure");
|
||||
add_debugger_command("cache", &dump_cache, "Dump cache_ref data structure");
|
||||
// add_debugger_command("dl", &display_mem, "dump memory long words (64-bit)");
|
||||
@ -2125,7 +1789,7 @@ vm_init_postsem(kernel_args *ka)
|
||||
// since we're still single threaded and only the kernel address space exists,
|
||||
// it isn't that hard to find all of the ones we need to create
|
||||
vm_translation_map_module_init_post_sem(ka);
|
||||
kernel_aspace->virtual_map.sem = create_sem(WRITE_COUNT, "kernel_aspacelock");
|
||||
vm_aspace_init_post_sem();
|
||||
recursive_lock_init(&kernel_aspace->translation_map.lock, "vm translation rlock");
|
||||
|
||||
for (region = kernel_aspace->virtual_map.region_list; region; region = region->aspace_next) {
|
||||
@ -2134,7 +1798,6 @@ vm_init_postsem(kernel_args *ka)
|
||||
}
|
||||
|
||||
region_hash_sem = create_sem(WRITE_COUNT, "region_hash_sem");
|
||||
aspace_hash_sem = create_sem(WRITE_COUNT, "aspace_hash_sem");
|
||||
|
||||
return heap_init_postsem(ka);
|
||||
}
|
||||
|
409
src/kernel/core/vm/vm_address_space.c
Normal file
409
src/kernel/core/vm/vm_address_space.c
Normal file
@ -0,0 +1,409 @@
|
||||
/*
|
||||
** Copyright 2002-2004, The Haiku Team. All rights reserved.
|
||||
** Distributed under the terms of the Haiku License.
|
||||
**
|
||||
** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||
** Distributed under the terms of the NewOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <OS.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <kerrors.h>
|
||||
#include <vm.h>
|
||||
#include <vm_priv.h>
|
||||
#include <vm_page.h>
|
||||
#include <vm_cache.h>
|
||||
#include <vm_store_anonymous_noswap.h>
|
||||
#include <vm_store_device.h>
|
||||
#include <vm_store_null.h>
|
||||
#include <file_cache.h>
|
||||
#include <memheap.h>
|
||||
#include <debug.h>
|
||||
#include <console.h>
|
||||
#include <int.h>
|
||||
#include <smp.h>
|
||||
#include <lock.h>
|
||||
#include <khash.h>
|
||||
#include <thread.h>
|
||||
#include <team.h>
|
||||
|
||||
#include <boot/stage2.h>
|
||||
#include <boot/elf.h>
|
||||
|
||||
#include <arch/cpu.h>
|
||||
#include <arch/vm.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//#define TRACE_VM
|
||||
#ifdef TRACE_VM
|
||||
# define TRACE(x) dprintf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
vm_address_space *kernel_aspace;
|
||||
|
||||
#define ASPACE_HASH_TABLE_SIZE 1024
|
||||
static aspace_id next_aspace_id;
|
||||
static void *aspace_table;
|
||||
static sem_id aspace_hash_sem;
|
||||
|
||||
|
||||
static void
|
||||
_dump_aspace(vm_address_space *aspace)
|
||||
{
|
||||
vm_region *region;
|
||||
|
||||
dprintf("dump of address space at %p:\n", aspace);
|
||||
dprintf("name: '%s'\n", aspace->name);
|
||||
dprintf("id: 0x%lx\n", aspace->id);
|
||||
dprintf("ref_count: %ld\n", aspace->ref_count);
|
||||
dprintf("fault_count: %ld\n", aspace->fault_count);
|
||||
dprintf("working_set_size: 0x%lx\n", aspace->working_set_size);
|
||||
dprintf("translation_map: %p\n", &aspace->translation_map);
|
||||
dprintf("virtual_map.base: 0x%lx\n", aspace->virtual_map.base);
|
||||
dprintf("virtual_map.size: 0x%lx\n", aspace->virtual_map.size);
|
||||
dprintf("virtual_map.change_count: 0x%x\n", aspace->virtual_map.change_count);
|
||||
dprintf("virtual_map.sem: 0x%lx\n", aspace->virtual_map.sem);
|
||||
dprintf("virtual_map.region_hint: %p\n", aspace->virtual_map.region_hint);
|
||||
dprintf("virtual_map.region_list:\n");
|
||||
for (region = aspace->virtual_map.region_list; region != NULL; region = region->aspace_next) {
|
||||
dprintf(" region 0x%lx: ", region->id);
|
||||
dprintf("base_addr = 0x%lx ", region->base);
|
||||
dprintf("size = 0x%lx ", region->size);
|
||||
dprintf("name = '%s' ", region->name);
|
||||
dprintf("lock = 0x%x\n", region->lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_aspace(int argc, char **argv)
|
||||
{
|
||||
// int i;
|
||||
vm_address_space *aspace;
|
||||
|
||||
if (argc < 2) {
|
||||
dprintf("aspace: not enough arguments\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if the argument looks like a hex number, treat it as such
|
||||
if (strlen(argv[1]) > 2 && argv[1][0] == '0' && argv[1][1] == 'x') {
|
||||
unsigned long num = atoul(argv[1]);
|
||||
aspace_id id = num;
|
||||
|
||||
aspace = hash_lookup(aspace_table, &id);
|
||||
if (aspace == NULL) {
|
||||
dprintf("invalid aspace id\n");
|
||||
} else {
|
||||
_dump_aspace(aspace);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
// walk through the aspace list, looking for the arguments as a name
|
||||
struct hash_iterator iter;
|
||||
|
||||
hash_open(aspace_table, &iter);
|
||||
while ((aspace = hash_next(aspace_table, &iter)) != NULL) {
|
||||
if(aspace->name != NULL && strcmp(argv[1], aspace->name) == 0) {
|
||||
_dump_aspace(aspace);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_aspace_list(int argc, char **argv)
|
||||
{
|
||||
vm_address_space *as;
|
||||
struct hash_iterator iter;
|
||||
|
||||
dprintf("addr\tid\t%32s\tbase\t\tsize\n", "name");
|
||||
|
||||
hash_open(aspace_table, &iter);
|
||||
while ((as = hash_next(aspace_table, &iter)) != NULL) {
|
||||
dprintf("%p\t0x%lx\t%32s\t0x%lx\t\t0x%lx\n",
|
||||
as, as->id, as->name, as->virtual_map.base, as->virtual_map.size);
|
||||
}
|
||||
hash_close(aspace_table, &iter, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
aspace_compare(void *_a, const void *key)
|
||||
{
|
||||
vm_address_space *aspace = _a;
|
||||
const aspace_id *id = key;
|
||||
|
||||
if (aspace->id == *id)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static uint32
|
||||
aspace_hash(void *_a, const void *key, uint32 range)
|
||||
{
|
||||
vm_address_space *aspace = _a;
|
||||
const aspace_id *id = key;
|
||||
|
||||
if(aspace != NULL)
|
||||
return (aspace->id % range);
|
||||
else
|
||||
return (*id % range);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
vm_address_space *
|
||||
vm_get_aspace_by_id(aspace_id aid)
|
||||
{
|
||||
vm_address_space *aspace;
|
||||
|
||||
acquire_sem_etc(aspace_hash_sem, READ_COUNT, 0, 0);
|
||||
aspace = hash_lookup(aspace_table, &aid);
|
||||
if (aspace)
|
||||
atomic_add(&aspace->ref_count, 1);
|
||||
release_sem_etc(aspace_hash_sem, READ_COUNT, 0);
|
||||
|
||||
return aspace;
|
||||
}
|
||||
|
||||
|
||||
vm_address_space *
|
||||
vm_get_kernel_aspace(void)
|
||||
{
|
||||
/* we can treat this one a little differently since it can't be deleted */
|
||||
acquire_sem_etc(aspace_hash_sem, READ_COUNT, 0, 0);
|
||||
atomic_add(&kernel_aspace->ref_count, 1);
|
||||
release_sem_etc(aspace_hash_sem, READ_COUNT, 0);
|
||||
return kernel_aspace;
|
||||
}
|
||||
|
||||
|
||||
aspace_id
|
||||
vm_get_kernel_aspace_id(void)
|
||||
{
|
||||
return kernel_aspace->id;
|
||||
}
|
||||
|
||||
|
||||
vm_address_space *
|
||||
vm_get_current_user_aspace(void)
|
||||
{
|
||||
return vm_get_aspace_by_id(vm_get_current_user_aspace_id());
|
||||
}
|
||||
|
||||
|
||||
aspace_id
|
||||
vm_get_current_user_aspace_id(void)
|
||||
{
|
||||
struct thread *t = thread_get_current_thread();
|
||||
|
||||
if (t)
|
||||
return t->team->_aspace_id;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
vm_put_aspace(vm_address_space *aspace)
|
||||
{
|
||||
// vm_region *region;
|
||||
bool removeit = false;
|
||||
|
||||
acquire_sem_etc(aspace_hash_sem, WRITE_COUNT, 0, 0);
|
||||
if (atomic_add(&aspace->ref_count, -1) == 1) {
|
||||
hash_remove(aspace_table, aspace);
|
||||
removeit = true;
|
||||
}
|
||||
release_sem_etc(aspace_hash_sem, WRITE_COUNT, 0);
|
||||
|
||||
if (!removeit)
|
||||
return;
|
||||
|
||||
TRACE(("vm_put_aspace: reached zero ref, deleting aspace\n"));
|
||||
|
||||
if (aspace == kernel_aspace)
|
||||
panic("vm_put_aspace: tried to delete the kernel aspace!\n");
|
||||
|
||||
if (aspace->virtual_map.region_list)
|
||||
panic("vm_put_aspace: aspace at %p has zero ref count, but region list isn't empty!\n", aspace);
|
||||
|
||||
(*aspace->translation_map.ops->destroy)(&aspace->translation_map);
|
||||
|
||||
free(aspace->name);
|
||||
delete_sem(aspace->virtual_map.sem);
|
||||
free(aspace);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
aspace_id
|
||||
vm_create_aspace(const char *name, addr_t base, addr_t size, bool kernel)
|
||||
{
|
||||
vm_address_space *aspace;
|
||||
int err;
|
||||
|
||||
|
||||
aspace = (vm_address_space *)malloc(sizeof(vm_address_space));
|
||||
if (aspace == NULL)
|
||||
return ENOMEM;
|
||||
|
||||
TRACE(("vm_create_aspace: %s: %lx bytes starting at 0x%lx => %p\n", name, size, base, aspace));
|
||||
|
||||
aspace->name = (char *)malloc(strlen(name) + 1);
|
||||
if (aspace->name == NULL ) {
|
||||
free(aspace);
|
||||
return ENOMEM;
|
||||
}
|
||||
strcpy(aspace->name, name);
|
||||
|
||||
aspace->id = next_aspace_id++;
|
||||
aspace->ref_count = 1;
|
||||
aspace->state = VM_ASPACE_STATE_NORMAL;
|
||||
aspace->fault_count = 0;
|
||||
aspace->scan_va = base;
|
||||
aspace->working_set_size = kernel ? DEFAULT_KERNEL_WORKING_SET : DEFAULT_WORKING_SET;
|
||||
aspace->max_working_set = DEFAULT_MAX_WORKING_SET;
|
||||
aspace->min_working_set = DEFAULT_MIN_WORKING_SET;
|
||||
aspace->last_working_set_adjust = system_time();
|
||||
|
||||
// initialize the corresponding translation map
|
||||
err = vm_translation_map_create(&aspace->translation_map, kernel);
|
||||
if (err < 0) {
|
||||
free(aspace->name);
|
||||
free(aspace);
|
||||
return err;
|
||||
}
|
||||
|
||||
// initialize the virtual map
|
||||
aspace->virtual_map.base = base;
|
||||
aspace->virtual_map.size = size;
|
||||
aspace->virtual_map.region_list = NULL;
|
||||
aspace->virtual_map.region_hint = NULL;
|
||||
aspace->virtual_map.change_count = 0;
|
||||
aspace->virtual_map.sem = create_sem(WRITE_COUNT, "aspacelock");
|
||||
aspace->virtual_map.aspace = aspace;
|
||||
|
||||
// add the aspace to the global hash table
|
||||
acquire_sem_etc(aspace_hash_sem, WRITE_COUNT, 0, 0);
|
||||
hash_insert(aspace_table, aspace);
|
||||
release_sem_etc(aspace_hash_sem, WRITE_COUNT, 0);
|
||||
|
||||
return aspace->id;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
vm_delete_aspace(aspace_id aid)
|
||||
{
|
||||
vm_address_space *aspace;
|
||||
|
||||
aspace = vm_get_aspace_by_id(aid);
|
||||
if (aspace == NULL)
|
||||
return ERR_VM_INVALID_ASPACE;
|
||||
|
||||
TRACE(("vm_delete_aspace: called on aspace 0x%lx\n", aid));
|
||||
|
||||
// put this aspace in the deletion state
|
||||
// this guarantees that no one else will add regions to the list
|
||||
acquire_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0, 0);
|
||||
if (aspace->state == VM_ASPACE_STATE_DELETION) {
|
||||
// abort, someone else is already deleting this aspace
|
||||
release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0);
|
||||
vm_put_aspace(aspace);
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
aspace->state = VM_ASPACE_STATE_DELETION;
|
||||
|
||||
vm_delete_areas(aspace);
|
||||
|
||||
// unlock
|
||||
release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0);
|
||||
|
||||
// release two refs on the address space
|
||||
vm_put_aspace(aspace);
|
||||
vm_put_aspace(aspace);
|
||||
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
vm_aspace_walk_start(struct hash_iterator *i)
|
||||
{
|
||||
hash_open(aspace_table, i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
vm_address_space *
|
||||
vm_aspace_walk_next(struct hash_iterator *i)
|
||||
{
|
||||
vm_address_space *aspace;
|
||||
|
||||
acquire_sem_etc(aspace_hash_sem, READ_COUNT, 0, 0);
|
||||
aspace = hash_next(aspace_table, i);
|
||||
if (aspace)
|
||||
atomic_add(&aspace->ref_count, 1);
|
||||
release_sem_etc(aspace_hash_sem, READ_COUNT, 0);
|
||||
return aspace;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
vm_aspace_init(void)
|
||||
{
|
||||
next_aspace_id = 0;
|
||||
aspace_hash_sem = -1;
|
||||
|
||||
// create the region and address space hash tables
|
||||
{
|
||||
vm_address_space *aspace;
|
||||
aspace_table = hash_init(ASPACE_HASH_TABLE_SIZE, (addr_t)&aspace->hash_next - (addr_t)aspace,
|
||||
&aspace_compare, &aspace_hash);
|
||||
if (aspace_table == NULL)
|
||||
panic("vm_init: error creating aspace hash table\n");
|
||||
}
|
||||
|
||||
kernel_aspace = NULL;
|
||||
|
||||
// create the initial kernel address space
|
||||
{
|
||||
aspace_id aid;
|
||||
aid = vm_create_aspace("kernel_land", KERNEL_BASE, KERNEL_SIZE, true);
|
||||
if (aid < 0)
|
||||
panic("vm_init: error creating kernel address space!\n");
|
||||
kernel_aspace = vm_get_aspace_by_id(aid);
|
||||
vm_put_aspace(kernel_aspace);
|
||||
}
|
||||
|
||||
add_debugger_command("aspaces", &dump_aspace_list, "Dump a list of all address spaces");
|
||||
add_debugger_command("aspace", &dump_aspace, "Dump info about a particular address space");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
vm_aspace_init_post_sem(void)
|
||||
{
|
||||
kernel_aspace->virtual_map.sem = create_sem(WRITE_COUNT, "kernel_aspacelock");
|
||||
aspace_hash_sem = create_sem(WRITE_COUNT, "aspace_hash_sem");
|
||||
}
|
Loading…
Reference in New Issue
Block a user