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:
Axel Dörfler 2004-06-09 00:05:02 +00:00
parent 591af8735d
commit 98b3dfb3e1

View File

@ -184,19 +184,28 @@ region_id vm_find_region_by_name(aspace_id aid, const char *name)
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;
// 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));
if(region == NULL)
if (region == NULL)
return NULL;
region->name = (char *)malloc(strlen(name) + 1);
if(region->name == NULL) {
region->name = (char *)malloc(length);
if (region->name == NULL) {
free(region);
return NULL;
}
strcpy(region->name, name);
strlcpy(region->name, name, length);
region->id = atomic_add(&next_region_id, 1);
region->base = 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
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)
{
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->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;
}
{
addr_t search_addr, search_end;
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;
}
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;
}
err = insert_area(aspace, vaddr, addr_type, size, region);
if (err < B_OK)
goto err1b;
// attach the cache to the region
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
vm_create_anonymous_region(aspace_id aid, const char *name, void **address,
int addr_type, addr_t size, int wiring, int lock)