- Removed B_EXACT_KERNEL_ADDRESS - doesn't make that much sense (it was a private
and (very) temporary extension, anyway). - Fixed _user_create_area() - it will now also recognize B_ANY_KERNEL_BLOCK_AREA, and it will not access a kernel address for B_EXACT_ADDRESS. - create_area() will now handle B_EXACT_ADDRESS correctly as well. - get_memory_map() will now silently ignore the missing final entry if the map contains only one entry. - The check for user memory was wrong in get_memory_map(); it worked, but it was not necessarily portable. - vm_reserve_address_range() was not correctly initializing the region. - find_and_insert_region_slot() will now search for reserved regions when B_EXACT_ADDRESS is used - not yet tested, though. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7871 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+129
-24
@@ -185,6 +185,22 @@ region_id vm_find_region_by_name(aspace_id aid, const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static vm_region *
|
||||||
|
_vm_create_reserved_region_struct(vm_virtual_map *map)
|
||||||
|
{
|
||||||
|
vm_region *reserved = malloc(sizeof(vm_region));
|
||||||
|
if (reserved == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(reserved, 0, sizeof(vm_region));
|
||||||
|
reserved->id = -1;
|
||||||
|
// this marks it as reserved space
|
||||||
|
reserved->map = map;
|
||||||
|
|
||||||
|
return reserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static vm_region *
|
static vm_region *
|
||||||
_vm_create_region_struct(vm_address_space *aspace, const char *name, int wiring, int lock)
|
_vm_create_region_struct(vm_address_space *aspace, const char *name, int wiring, int lock)
|
||||||
{
|
{
|
||||||
@@ -226,7 +242,83 @@ _vm_create_region_struct(vm_address_space *aspace, const char *name, int wiring,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
find_reserved_region(vm_virtual_map *map, addr_t start, addr_t size, vm_region *region)
|
||||||
|
{
|
||||||
|
vm_region *next, *last = NULL;
|
||||||
|
|
||||||
|
next = map->region_list;
|
||||||
|
while (next) {
|
||||||
|
if (next->base <= start && next->base + next->size >= start + size) {
|
||||||
|
// this region covers the requested range
|
||||||
|
if (next->id != -1) {
|
||||||
|
// but it's not reserved space, it's a real region
|
||||||
|
return ERR_VM_NO_REGION_SLOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last = next;
|
||||||
|
next = next->aspace_next;
|
||||||
|
}
|
||||||
|
if (next == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
// now we have to transfer the requested part of the reserved
|
||||||
|
// range to the new region - and remove, resize or split the old
|
||||||
|
// reserved region.
|
||||||
|
|
||||||
|
if (start == next->base) {
|
||||||
|
// the region starts at the beginning of the reserved range
|
||||||
|
if (last)
|
||||||
|
last->aspace_next = region;
|
||||||
|
else
|
||||||
|
map->region_list = region;
|
||||||
|
|
||||||
|
if (size == next->size) {
|
||||||
|
// the new region fully covers the reversed range
|
||||||
|
region->aspace_next = next->aspace_next;
|
||||||
|
free(next);
|
||||||
|
} else {
|
||||||
|
// resize the reserved range behind the region
|
||||||
|
region->aspace_next = next;
|
||||||
|
next->base += size;
|
||||||
|
next->size -= size;
|
||||||
|
}
|
||||||
|
} else if (start + size == next->base + next->size) {
|
||||||
|
// the region is at the end of the reserved range
|
||||||
|
region->aspace_next = next->aspace_next;
|
||||||
|
next->aspace_next = region;
|
||||||
|
|
||||||
|
// resize the reserved range before the region
|
||||||
|
next->size = start - next->base;
|
||||||
|
} else {
|
||||||
|
// the region splits the reserved range into two separate ones
|
||||||
|
// we need a new reserved region to cover this space
|
||||||
|
vm_region *reserved = _vm_create_reserved_region_struct(map);
|
||||||
|
if (reserved == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
reserved->aspace_next = next->aspace_next;
|
||||||
|
region->aspace_next = reserved;
|
||||||
|
next->aspace_next = region;
|
||||||
|
|
||||||
|
// resize regions
|
||||||
|
reserved->size = next->base + next->size - start - size;
|
||||||
|
next->size = start - next->base;
|
||||||
|
reserved->base = start + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
region->base = start;
|
||||||
|
region->size = size;
|
||||||
|
map->change_count++;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 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 status_t
|
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)
|
||||||
{
|
{
|
||||||
@@ -236,11 +328,20 @@ find_and_insert_region_slot(vm_virtual_map *map, addr_t start, addr_t size, addr
|
|||||||
|
|
||||||
TRACE(("find_and_insert_region_slot: map %p, start 0x%lx, size %ld, end 0x%lx, addr_type %d, region %p\n",
|
TRACE(("find_and_insert_region_slot: map %p, start 0x%lx, size %ld, end 0x%lx, addr_type %d, region %p\n",
|
||||||
map, start, size, end, addr_type, region));
|
map, start, size, end, addr_type, region));
|
||||||
// dprintf("map->base 0x%x, map->size 0x%x\n", map->base, map->size);
|
|
||||||
|
|
||||||
// do some sanity checking
|
// do some sanity checking
|
||||||
if (start < map->base || size == 0 || (end - 1) > (map->base + (map->size - 1)) || start + size > end)
|
if (start < map->base || size == 0 || (end - 1) > (map->base + (map->size - 1)) || start + size > end)
|
||||||
return ERR_VM_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
if (addr_type == B_EXACT_ADDRESS) {
|
||||||
|
// search for a reserved region
|
||||||
|
status_t status = find_reserved_region(map, start, size, region);
|
||||||
|
if (status == B_OK || status == ERR_VM_NO_REGION_SLOT)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
// there was no reserved region, and the slot doesn't seem to be used already
|
||||||
|
// ToDo: this could be further optimized.
|
||||||
|
}
|
||||||
|
|
||||||
// walk up to the spot where we should start searching
|
// walk up to the spot where we should start searching
|
||||||
next_r = map->region_list;
|
next_r = map->region_list;
|
||||||
@@ -294,7 +395,6 @@ find_and_insert_region_slot(vm_virtual_map *map, addr_t start, addr_t size, addr
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case B_EXACT_ADDRESS:
|
case B_EXACT_ADDRESS:
|
||||||
case B_EXACT_KERNEL_ADDRESS:
|
|
||||||
// see if we can create it exactly here
|
// see if we can create it exactly here
|
||||||
if (!last_r) {
|
if (!last_r) {
|
||||||
if (!next_r || (next_r->base >= start + size)) {
|
if (!next_r || (next_r->base >= start + size)) {
|
||||||
@@ -318,7 +418,7 @@ find_and_insert_region_slot(vm_virtual_map *map, addr_t start, addr_t size, addr
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return EINVAL;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foundspot)
|
if (!foundspot)
|
||||||
@@ -353,7 +453,6 @@ insert_area(vm_address_space *addressSpace, void **_address,
|
|||||||
|
|
||||||
switch (addressSpec) {
|
switch (addressSpec) {
|
||||||
case B_EXACT_ADDRESS:
|
case B_EXACT_ADDRESS:
|
||||||
case B_EXACT_KERNEL_ADDRESS:
|
|
||||||
searchBase = (addr_t)*_address;
|
searchBase = (addr_t)*_address;
|
||||||
searchEnd = (addr_t)*_address + size;
|
searchEnd = (addr_t)*_address + size;
|
||||||
break;
|
break;
|
||||||
@@ -534,16 +633,12 @@ vm_reserve_address_range(aspace_id aid, void **_address, uint32 addressSpec, add
|
|||||||
if (addressSpace == NULL)
|
if (addressSpace == NULL)
|
||||||
return ERR_VM_INVALID_ASPACE;
|
return ERR_VM_INVALID_ASPACE;
|
||||||
|
|
||||||
area = malloc(sizeof(vm_region));
|
area = _vm_create_reserved_region_struct(&addressSpace->virtual_map);
|
||||||
if (area == NULL) {
|
if (area == NULL) {
|
||||||
status = B_NO_MEMORY;
|
status = B_NO_MEMORY;
|
||||||
goto err1;
|
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);
|
acquire_sem_etc(addressSpace->virtual_map.sem, WRITE_COUNT, 0, 0);
|
||||||
|
|
||||||
// check to see if this aspace has entered DELETE state
|
// check to see if this aspace has entered DELETE state
|
||||||
@@ -591,7 +686,6 @@ vm_create_anonymous_region(aspace_id aid, const char *name, void **address,
|
|||||||
case B_EXACT_ADDRESS:
|
case B_EXACT_ADDRESS:
|
||||||
case B_BASE_ADDRESS:
|
case B_BASE_ADDRESS:
|
||||||
case B_ANY_KERNEL_ADDRESS:
|
case B_ANY_KERNEL_ADDRESS:
|
||||||
case B_EXACT_KERNEL_ADDRESS:
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -1775,12 +1869,12 @@ create_preloaded_image_areas(struct preloaded_image *image)
|
|||||||
memcpy(name, fileName, length);
|
memcpy(name, fileName, length);
|
||||||
strcpy(name + length, "_text");
|
strcpy(name + length, "_text");
|
||||||
address = (void *)ROUNDOWN(image->text_region.start, PAGE_SIZE);
|
address = (void *)ROUNDOWN(image->text_region.start, PAGE_SIZE);
|
||||||
image->text_region.id = vm_create_anonymous_region(vm_get_kernel_aspace_id(), name, &address, B_EXACT_KERNEL_ADDRESS,
|
image->text_region.id = vm_create_anonymous_region(vm_get_kernel_aspace_id(), name, &address, B_EXACT_ADDRESS,
|
||||||
PAGE_ALIGN(image->text_region.size), B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
PAGE_ALIGN(image->text_region.size), B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
|
||||||
strcpy(name + length, "_data");
|
strcpy(name + length, "_data");
|
||||||
address = (void *)ROUNDOWN(image->data_region.start, PAGE_SIZE);
|
address = (void *)ROUNDOWN(image->data_region.start, PAGE_SIZE);
|
||||||
image->data_region.id = vm_create_anonymous_region(vm_get_kernel_aspace_id(), name, &address, B_EXACT_KERNEL_ADDRESS,
|
image->data_region.id = vm_create_anonymous_region(vm_get_kernel_aspace_id(), name, &address, B_EXACT_ADDRESS,
|
||||||
PAGE_ALIGN(image->data_region.size), B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
PAGE_ALIGN(image->data_region.size), B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1853,7 +1947,7 @@ vm_init(kernel_args *ka)
|
|||||||
// allocate regions to represent stuff that already exists
|
// allocate regions to represent stuff that already exists
|
||||||
|
|
||||||
address = (void *)ROUNDOWN(heap_base, PAGE_SIZE);
|
address = (void *)ROUNDOWN(heap_base, PAGE_SIZE);
|
||||||
vm_create_anonymous_region(vm_get_kernel_aspace_id(), "kernel_heap", &address, B_EXACT_KERNEL_ADDRESS,
|
vm_create_anonymous_region(vm_get_kernel_aspace_id(), "kernel_heap", &address, B_EXACT_ADDRESS,
|
||||||
HEAP_SIZE, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
HEAP_SIZE, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
|
|
||||||
ka->kernel_image.name = "kernel";
|
ka->kernel_image.name = "kernel";
|
||||||
@@ -1871,7 +1965,7 @@ vm_init(kernel_args *ka)
|
|||||||
|
|
||||||
sprintf(temp, "idle_thread%d_kstack", i);
|
sprintf(temp, "idle_thread%d_kstack", i);
|
||||||
address = (void *)ka->cpu_kstack[i].start;
|
address = (void *)ka->cpu_kstack[i].start;
|
||||||
vm_create_anonymous_region(vm_get_kernel_aspace_id(), temp, &address, B_EXACT_KERNEL_ADDRESS,
|
vm_create_anonymous_region(vm_get_kernel_aspace_id(), temp, &address, B_EXACT_ADDRESS,
|
||||||
ka->cpu_kstack[i].size, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
ka->cpu_kstack[i].size, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -2407,7 +2501,7 @@ get_memory_map(const void *address, ulong numBytes, physical_entry *table, long
|
|||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
// in which address space is the address to be found?
|
// in which address space is the address to be found?
|
||||||
if (virtualAddress < KERNEL_BASE)
|
if (IS_USER_ADDRESS(virtualAddress))
|
||||||
addressSpace = vm_get_current_user_aspace();
|
addressSpace = vm_get_current_user_aspace();
|
||||||
else
|
else
|
||||||
addressSpace = vm_get_kernel_aspace();
|
addressSpace = vm_get_kernel_aspace();
|
||||||
@@ -2452,6 +2546,10 @@ get_memory_map(const void *address, ulong numBytes, physical_entry *table, long
|
|||||||
// close the entry list
|
// close the entry list
|
||||||
|
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
|
// if it's only one entry, we will silently accept the missing ending
|
||||||
|
if (numEntries == 1)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
if (++index + 1 > numEntries)
|
if (++index + 1 > numEntries)
|
||||||
return B_BUFFER_OVERFLOW;
|
return B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
@@ -2564,10 +2662,11 @@ create_area_etc(struct team *team, const char *name, void **address, uint32 addr
|
|||||||
|
|
||||||
|
|
||||||
area_id
|
area_id
|
||||||
create_area(const char *name, void **address, uint32 addressSpec, size_t size, uint32 lock,
|
create_area(const char *name, void **_address, uint32 addressSpec, size_t size, uint32 lock,
|
||||||
uint32 protection)
|
uint32 protection)
|
||||||
{
|
{
|
||||||
aspace_id areaSpace;
|
aspace_id addressSpace;
|
||||||
|
bool kernel = false;
|
||||||
|
|
||||||
if ((protection & B_KERNEL_PROTECTION) == 0)
|
if ((protection & B_KERNEL_PROTECTION) == 0)
|
||||||
protection |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA;
|
protection |= B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA;
|
||||||
@@ -2575,15 +2674,17 @@ create_area(const char *name, void **address, uint32 addressSpec, size_t size, u
|
|||||||
switch (addressSpec) {
|
switch (addressSpec) {
|
||||||
case B_ANY_KERNEL_BLOCK_ADDRESS:
|
case B_ANY_KERNEL_BLOCK_ADDRESS:
|
||||||
case B_ANY_KERNEL_ADDRESS:
|
case B_ANY_KERNEL_ADDRESS:
|
||||||
case B_EXACT_KERNEL_ADDRESS:
|
kernel = true;
|
||||||
areaSpace = vm_get_kernel_aspace_id();
|
|
||||||
break;
|
break;
|
||||||
default:
|
case B_EXACT_ADDRESS:
|
||||||
areaSpace = vm_get_current_user_aspace_id();
|
if (IS_KERNEL_ADDRESS(*_address))
|
||||||
|
kernel = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return vm_create_anonymous_region(areaSpace, (char *)name, address,
|
addressSpace = kernel ? vm_get_kernel_aspace_id() : vm_get_current_user_aspace_id();
|
||||||
|
|
||||||
|
return vm_create_anonymous_region(addressSpace, (char *)name, _address,
|
||||||
addressSpec, size, lock, protection);
|
addressSpec, size, lock, protection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2702,7 +2803,7 @@ _user_create_area(const char *userName, void **userAddress, uint32 addressSpec,
|
|||||||
// filter out some unavailable values (for userland)
|
// filter out some unavailable values (for userland)
|
||||||
switch (addressSpec) {
|
switch (addressSpec) {
|
||||||
case B_ANY_KERNEL_ADDRESS:
|
case B_ANY_KERNEL_ADDRESS:
|
||||||
case B_EXACT_KERNEL_ADDRESS:
|
case B_ANY_KERNEL_BLOCK_ADDRESS:
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
if (protection & B_KERNEL_PROTECTION)
|
if (protection & B_KERNEL_PROTECTION)
|
||||||
@@ -2714,6 +2815,10 @@ _user_create_area(const char *userName, void **userAddress, uint32 addressSpec,
|
|||||||
|| user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
|
|| user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
if (addressSpec == B_EXACT_ADDRESS
|
||||||
|
&& IS_KERNEL_ADDRESS(address))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
area = create_area(name, &address, addressSpec, size, lock, protection);
|
area = create_area(name, &address, addressSpec, size, lock, protection);
|
||||||
|
|
||||||
if (area >= B_OK && user_memcpy(userAddress, &address, sizeof(address)) < B_OK) {
|
if (area >= B_OK && user_memcpy(userAddress, &address, sizeof(address)) < B_OK) {
|
||||||
|
|||||||
Reference in New Issue
Block a user