Extracted the address specification stuff out of map_backing_store() and
created a call around find_and_insert_region_slot() that takes care of everything. Fixed B_BASE_ADDRESS support (it now really works). First shot at a new VM function vm_reserve_address_range() that will be used to fix our ELF loader issues (which needs to create adjacent regions which the VM cannot guaranty at this point). git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7870 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+113
-31
@@ -184,19 +184,28 @@ region_id vm_find_region_by_name(aspace_id aid, const char *name)
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static vm_region *_vm_create_region_struct(vm_address_space *aspace, const char *name, int wiring, int lock)
|
|
||||||
|
static vm_region *
|
||||||
|
_vm_create_region_struct(vm_address_space *aspace, const char *name, int wiring, int lock)
|
||||||
{
|
{
|
||||||
vm_region *region = NULL;
|
vm_region *region = NULL;
|
||||||
|
|
||||||
|
// restrict the area name to B_OS_NAME_LENGTH
|
||||||
|
size_t length = strlen(name) + 1;
|
||||||
|
if (length > B_OS_NAME_LENGTH)
|
||||||
|
length = B_OS_NAME_LENGTH;
|
||||||
|
|
||||||
region = (vm_region *)malloc(sizeof(vm_region));
|
region = (vm_region *)malloc(sizeof(vm_region));
|
||||||
if (region == NULL)
|
if (region == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
region->name = (char *)malloc(strlen(name) + 1);
|
|
||||||
|
region->name = (char *)malloc(length);
|
||||||
if (region->name == NULL) {
|
if (region->name == NULL) {
|
||||||
free(region);
|
free(region);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
strcpy(region->name, name);
|
strlcpy(region->name, name, length);
|
||||||
|
|
||||||
region->id = atomic_add(&next_region_id, 1);
|
region->id = atomic_add(&next_region_id, 1);
|
||||||
region->base = 0;
|
region->base = 0;
|
||||||
region->size = 0;
|
region->size = 0;
|
||||||
@@ -218,7 +227,7 @@ static vm_region *_vm_create_region_struct(vm_address_space *aspace, const char
|
|||||||
|
|
||||||
|
|
||||||
// must be called with this address space's virtual_map.sem held
|
// must be called with this address space's virtual_map.sem held
|
||||||
static int
|
static status_t
|
||||||
find_and_insert_region_slot(vm_virtual_map *map, addr_t start, addr_t size, addr_t end, int addr_type, vm_region *region)
|
find_and_insert_region_slot(vm_virtual_map *map, addr_t start, addr_t size, addr_t end, int addr_type, vm_region *region)
|
||||||
{
|
{
|
||||||
vm_region *last_r = NULL;
|
vm_region *last_r = NULL;
|
||||||
@@ -324,7 +333,55 @@ find_and_insert_region_slot(vm_virtual_map *map, addr_t start, addr_t size, addr
|
|||||||
map->region_list = region;
|
map->region_list = region;
|
||||||
}
|
}
|
||||||
map->change_count++;
|
map->change_count++;
|
||||||
return B_NO_ERROR;
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** This inserts the area/region you pass into the virtual_map of the
|
||||||
|
* specified address space.
|
||||||
|
* It will also set the "_address" argument to its base address when
|
||||||
|
* the call succeeds.
|
||||||
|
* You need to hold the virtual_map semaphore.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
insert_area(vm_address_space *addressSpace, void **_address,
|
||||||
|
uint32 addressSpec, addr_t size, vm_region *area)
|
||||||
|
{
|
||||||
|
addr_t searchBase, searchEnd;
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
switch (addressSpec) {
|
||||||
|
case B_EXACT_ADDRESS:
|
||||||
|
case B_EXACT_KERNEL_ADDRESS:
|
||||||
|
searchBase = (addr_t)*_address;
|
||||||
|
searchEnd = (addr_t)*_address + size;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_BASE_ADDRESS:
|
||||||
|
searchBase = (addr_t)*_address;
|
||||||
|
searchEnd = addressSpace->virtual_map.base + (addressSpace->virtual_map.size - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_ANY_ADDRESS:
|
||||||
|
case B_ANY_KERNEL_ADDRESS:
|
||||||
|
case B_ANY_KERNEL_BLOCK_ADDRESS:
|
||||||
|
searchBase = addressSpace->virtual_map.base;
|
||||||
|
searchEnd = addressSpace->virtual_map.base + (addressSpace->virtual_map.size - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = find_and_insert_region_slot(&addressSpace->virtual_map, searchBase, size,
|
||||||
|
searchEnd, addressSpec, area);
|
||||||
|
if (status == B_OK)
|
||||||
|
// ToDo: do we have to do anything about B_ANY_KERNEL_ADDRESS
|
||||||
|
// vs. B_ANY_KERNEL_BLOCK_ADDRESS here?
|
||||||
|
*_address = (void *)area->base;
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -424,33 +481,9 @@ map_backing_store(vm_address_space *aspace, vm_store *store, void **vaddr,
|
|||||||
goto err1b;
|
goto err1b;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
err = insert_area(aspace, vaddr, addr_type, size, region);
|
||||||
addr_t search_addr, search_end;
|
if (err < B_OK)
|
||||||
|
|
||||||
switch (addr_type) {
|
|
||||||
case B_EXACT_ADDRESS:
|
|
||||||
case B_EXACT_KERNEL_ADDRESS:
|
|
||||||
case B_BASE_ADDRESS:
|
|
||||||
search_addr = (addr_t)*vaddr;
|
|
||||||
search_end = (addr_t)*vaddr + size;
|
|
||||||
break;
|
|
||||||
case B_ANY_ADDRESS:
|
|
||||||
case B_ANY_KERNEL_ADDRESS:
|
|
||||||
case B_ANY_KERNEL_BLOCK_ADDRESS:
|
|
||||||
search_addr = aspace->virtual_map.base;
|
|
||||||
search_end = aspace->virtual_map.base + (aspace->virtual_map.size - 1);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
err = EINVAL;
|
|
||||||
goto err1b;
|
goto err1b;
|
||||||
}
|
|
||||||
|
|
||||||
err = find_and_insert_region_slot(&aspace->virtual_map, search_addr, size,
|
|
||||||
search_end, addr_type, region);
|
|
||||||
if (err < 0)
|
|
||||||
goto err1b;
|
|
||||||
*vaddr = (addr_t *)region->base;
|
|
||||||
}
|
|
||||||
|
|
||||||
// attach the cache to the region
|
// attach the cache to the region
|
||||||
region->cache_ref = cache_ref;
|
region->cache_ref = cache_ref;
|
||||||
@@ -490,6 +523,55 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
vm_reserve_address_range(aspace_id aid, void **_address, uint32 addressSpec, addr_t size)
|
||||||
|
{
|
||||||
|
vm_address_space *addressSpace;
|
||||||
|
vm_region *area;
|
||||||
|
status_t status = B_OK;
|
||||||
|
|
||||||
|
addressSpace = vm_get_aspace_by_id(aid);
|
||||||
|
if (addressSpace == NULL)
|
||||||
|
return ERR_VM_INVALID_ASPACE;
|
||||||
|
|
||||||
|
area = malloc(sizeof(vm_region));
|
||||||
|
if (area == NULL) {
|
||||||
|
status = B_NO_MEMORY;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
area->id = -1;
|
||||||
|
// this marks it as reserved space
|
||||||
|
area->map = &addressSpace->virtual_map;
|
||||||
|
|
||||||
|
acquire_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0, 0);
|
||||||
|
|
||||||
|
// check to see if this aspace has entered DELETE state
|
||||||
|
if (addressSpace->state == VM_ASPACE_STATE_DELETION) {
|
||||||
|
// okay, someone is trying to delete this aspace now, so we can't
|
||||||
|
// insert the region, so back out
|
||||||
|
status = ERR_VM_INVALID_ASPACE;
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = insert_area(addressSpace, _address, addressSpec, size, area);
|
||||||
|
if (status < B_OK)
|
||||||
|
goto err2;
|
||||||
|
|
||||||
|
// the region is now reserved!
|
||||||
|
|
||||||
|
release_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0);
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
err2:
|
||||||
|
release_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0);
|
||||||
|
free(area);
|
||||||
|
err1:
|
||||||
|
vm_put_aspace(addressSpace);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
region_id
|
region_id
|
||||||
vm_create_anonymous_region(aspace_id aid, const char *name, void **address,
|
vm_create_anonymous_region(aspace_id aid, const char *name, void **address,
|
||||||
int addr_type, addr_t size, int wiring, int lock)
|
int addr_type, addr_t size, int wiring, int lock)
|
||||||
|
|||||||
Reference in New Issue
Block a user