- 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:
Axel Dörfler 2004-06-09 01:04:51 +00:00
parent 98b3dfb3e1
commit 76377cf3f5

View File

@ -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 *
_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
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)
{
@ -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",
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
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
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;
case B_EXACT_ADDRESS:
case B_EXACT_KERNEL_ADDRESS:
// see if we can create it exactly here
if (!last_r) {
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;
default:
return EINVAL;
return B_BAD_VALUE;
}
if (!foundspot)
@ -353,7 +453,6 @@ insert_area(vm_address_space *addressSpace, void **_address,
switch (addressSpec) {
case B_EXACT_ADDRESS:
case B_EXACT_KERNEL_ADDRESS:
searchBase = (addr_t)*_address;
searchEnd = (addr_t)*_address + size;
break;
@ -534,16 +633,12 @@ vm_reserve_address_range(aspace_id aid, void **_address, uint32 addressSpec, add
if (addressSpace == NULL)
return ERR_VM_INVALID_ASPACE;
area = malloc(sizeof(vm_region));
area = _vm_create_reserved_region_struct(&addressSpace->virtual_map);
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
@ -591,7 +686,6 @@ vm_create_anonymous_region(aspace_id aid, const char *name, void **address,
case B_EXACT_ADDRESS:
case B_BASE_ADDRESS:
case B_ANY_KERNEL_ADDRESS:
case B_EXACT_KERNEL_ADDRESS:
break;
default:
@ -1775,12 +1869,12 @@ create_preloaded_image_areas(struct preloaded_image *image)
memcpy(name, fileName, length);
strcpy(name + length, "_text");
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);
strcpy(name + length, "_data");
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);
}
@ -1853,7 +1947,7 @@ vm_init(kernel_args *ka)
// allocate regions to represent stuff that already exists
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);
ka->kernel_image.name = "kernel";
@ -1871,7 +1965,7 @@ vm_init(kernel_args *ka)
sprintf(temp, "idle_thread%d_kstack", i);
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);
}
{
@ -2407,7 +2501,7 @@ get_memory_map(const void *address, ulong numBytes, physical_entry *table, long
return B_BAD_VALUE;
// 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();
else
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
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)
return B_BUFFER_OVERFLOW;
@ -2564,10 +2662,11 @@ create_area_etc(struct team *team, const char *name, void **address, uint32 addr
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)
{
aspace_id areaSpace;
aspace_id addressSpace;
bool kernel = false;
if ((protection & B_KERNEL_PROTECTION) == 0)
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) {
case B_ANY_KERNEL_BLOCK_ADDRESS:
case B_ANY_KERNEL_ADDRESS:
case B_EXACT_KERNEL_ADDRESS:
areaSpace = vm_get_kernel_aspace_id();
kernel = true;
break;
default:
areaSpace = vm_get_current_user_aspace_id();
case B_EXACT_ADDRESS:
if (IS_KERNEL_ADDRESS(*_address))
kernel = true;
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);
}
@ -2702,7 +2803,7 @@ _user_create_area(const char *userName, void **userAddress, uint32 addressSpec,
// filter out some unavailable values (for userland)
switch (addressSpec) {
case B_ANY_KERNEL_ADDRESS:
case B_EXACT_KERNEL_ADDRESS:
case B_ANY_KERNEL_BLOCK_ADDRESS:
return B_BAD_VALUE;
}
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)
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);
if (area >= B_OK && user_memcpy(userAddress, &address, sizeof(address)) < B_OK) {