* Cleanup, no functional change.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29478 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-03-12 12:18:25 +00:00
parent 5654f62097
commit e0b0a173b6
+183 -151
View File
@@ -1008,16 +1008,16 @@ create_area_struct(vm_address_space *addressSpace, const char *name,
} }
/** Finds a reserved area that covers the region spanned by \a start and /*! Finds a reserved area that covers the region spanned by \a start and
* \a size, inserts the \a area into that region and makes sure that \a size, inserts the \a area into that region and makes sure that
* there are reserved regions for the remaining parts. there are reserved regions for the remaining parts.
*/ */
static status_t static status_t
find_reserved_area(vm_address_space* addressSpace, addr_t start, find_reserved_area(vm_address_space* addressSpace, addr_t start,
addr_t size, vm_area* area) addr_t size, vm_area* area)
{ {
vm_area *next, *last = NULL; vm_area* last = NULL;
vm_area* next;
next = addressSpace->areas; next = addressSpace->areas;
while (next) { while (next) {
@@ -1120,7 +1120,7 @@ find_and_insert_area_slot(vm_address_space *addressSpace, addr_t start,
// There was no reserved area, and the slot doesn't seem to be used // There was no reserved area, and the slot doesn't seem to be used
// already // already
// ToDo: this could be further optimized. // TODO: this could be further optimized.
} }
size_t alignment = B_PAGE_SIZE; size_t alignment = B_PAGE_SIZE;
@@ -1184,12 +1184,13 @@ second_chance:
// We didn't find a free spot - if there were any reserved areas // We didn't find a free spot - if there were any reserved areas
// with the RESERVED_AVOID_BASE flag set, we can now test those // with the RESERVED_AVOID_BASE flag set, we can now test those
// for free space // for free space
// ToDo: it would make sense to start with the biggest of them // TODO: it would make sense to start with the biggest of them
next = addressSpace->areas; next = addressSpace->areas;
last = NULL; last = NULL;
for (last = NULL; next; next = next->address_space_next, for (last = NULL; next; next = next->address_space_next,
last = next) { last = next) {
// ToDo: take free space after the reserved area into account! // TODO: take free space after the reserved area into
// account!
if (next->base == ROUNDUP(next->base, alignment) if (next->base == ROUNDUP(next->base, alignment)
&& next->size == size) { && next->size == size) {
// The reserved area is entirely covered, and thus, // The reserved area is entirely covered, and thus,
@@ -1268,7 +1269,8 @@ second_chance:
} }
} else { } else {
if (next) { if (next) {
if (last->base + last->size <= start && next->base >= start + size) { if (last->base + last->size <= start
&& next->base >= start + size) {
foundSpot = true; foundSpot = true;
area->base = start; area->base = start;
break; break;
@@ -1342,7 +1344,7 @@ insert_area(vm_address_space *addressSpace, void **_address,
status = find_and_insert_area_slot(addressSpace, searchBase, size, status = find_and_insert_area_slot(addressSpace, searchBase, size,
searchEnd, addressSpec, area); searchEnd, addressSpec, area);
if (status == B_OK) { if (status == B_OK) {
// ToDo: do we have to do anything about B_ANY_KERNEL_ADDRESS // TODO: do we have to do anything about B_ANY_KERNEL_ADDRESS
// vs. B_ANY_KERNEL_BLOCK_ADDRESS here? // vs. B_ANY_KERNEL_BLOCK_ADDRESS here?
*_address = (void*)area->base; *_address = (void*)area->base;
} }
@@ -1573,9 +1575,10 @@ map_backing_store(vm_address_space *addressSpace, vm_cache *cache,
int wiring, int protection, int mapping, vm_area** _area, int wiring, int protection, int mapping, vm_area** _area,
const char* areaName, bool unmapAddressRange, bool kernel) const char* areaName, bool unmapAddressRange, bool kernel)
{ {
TRACE(("map_backing_store: aspace %p, cache %p, *vaddr %p, offset 0x%Lx, size %lu, addressSpec %ld, wiring %d, protection %d, _area %p, area_name '%s'\n", TRACE(("map_backing_store: aspace %p, cache %p, *vaddr %p, offset 0x%Lx, "
addressSpace, cache, *_virtualAddress, offset, size, addressSpec, "size %lu, addressSpec %ld, wiring %d, protection %d, area %p, areaName "
wiring, protection, _area, areaName)); "'%s'\n", addressSpace, cache, *_virtualAddress, offset, size,
addressSpec, wiring, protection, _area, areaName));
cache->AssertLocked(); cache->AssertLocked();
vm_area* area = create_area_struct(addressSpace, areaName, wiring, vm_area* area = create_area_struct(addressSpace, areaName, wiring,
@@ -1782,7 +1785,7 @@ vm_create_anonymous_area(team_id team, const char *name, void **address,
isStack = true; isStack = true;
#endif #endif
/* check parameters */ // check parameters
switch (addressSpec) { switch (addressSpec) {
case B_ANY_ADDRESS: case B_ANY_ADDRESS:
case B_EXACT_ADDRESS: case B_EXACT_ADDRESS:
@@ -1940,7 +1943,8 @@ vm_create_anonymous_area(team_id team, const char *name, void **address,
// Allocate and map all pages for this area // Allocate and map all pages for this area
off_t offset = 0; off_t offset = 0;
for (addr_t address = area->base; address < area->base + (area->size - 1); for (addr_t address = area->base;
address < area->base + (area->size - 1);
address += B_PAGE_SIZE, offset += B_PAGE_SIZE) { address += B_PAGE_SIZE, offset += B_PAGE_SIZE) {
#ifdef DEBUG_KERNEL_STACKS #ifdef DEBUG_KERNEL_STACKS
# ifdef STACK_GROWS_DOWNWARDS # ifdef STACK_GROWS_DOWNWARDS
@@ -1970,9 +1974,9 @@ vm_create_anonymous_area(team_id team, const char *name, void **address,
case B_ALREADY_WIRED: case B_ALREADY_WIRED:
{ {
// the pages should already be mapped. This is only really useful during // The pages should already be mapped. This is only really useful
// boot time. Find the appropriate vm_page objects and stick them in // during boot time. Find the appropriate vm_page objects and stick
// the cache object. // them in the cache object.
vm_translation_map* map = &addressSpace->translation_map; vm_translation_map* map = &addressSpace->translation_map;
off_t offset = 0; off_t offset = 0;
@@ -2009,8 +2013,8 @@ vm_create_anonymous_area(team_id team, const char *name, void **address,
case B_CONTIGUOUS: case B_CONTIGUOUS:
{ {
// We have already allocated our continuous pages run, so we can now just // We have already allocated our continuous pages run, so we can now
// map them in the address space // just map them in the address space
vm_translation_map* map = &addressSpace->translation_map; vm_translation_map* map = &addressSpace->translation_map;
addr_t physicalAddress = page->physical_page_number * B_PAGE_SIZE; addr_t physicalAddress = page->physical_page_number * B_PAGE_SIZE;
addr_t virtualAddress = area->base; addr_t virtualAddress = area->base;
@@ -2456,11 +2460,12 @@ vm_clone_area(team_id team, const char *name, void **address,
vm_cache* cache = vm_area_get_locked_cache(sourceArea); vm_cache* cache = vm_area_get_locked_cache(sourceArea);
// ToDo: for now, B_USER_CLONEABLE is disabled, until all drivers // TODO: for now, B_USER_CLONEABLE is disabled, until all drivers
// have been adapted. Maybe it should be part of the kernel settings, // have been adapted. Maybe it should be part of the kernel settings,
// anyway (so that old drivers can always work). // anyway (so that old drivers can always work).
#if 0 #if 0
if (sourceArea->aspace == vm_kernel_address_space() && addressSpace != vm_kernel_address_space() if (sourceArea->aspace == vm_kernel_address_space()
&& addressSpace != vm_kernel_address_space()
&& !(sourceArea->protection & B_USER_CLONEABLE_AREA)) { && !(sourceArea->protection & B_USER_CLONEABLE_AREA)) {
// kernel areas must not be cloned in userland, unless explicitly // kernel areas must not be cloned in userland, unless explicitly
// declared user-cloneable upon construction // declared user-cloneable upon construction
@@ -2486,7 +2491,8 @@ vm_clone_area(team_id team, const char *name, void **address,
// we need to map in everything at this point // we need to map in everything at this point
if (sourceArea->cache_type == CACHE_TYPE_DEVICE) { if (sourceArea->cache_type == CACHE_TYPE_DEVICE) {
// we don't have actual pages to map but a physical area // we don't have actual pages to map but a physical area
vm_translation_map *map = &sourceArea->address_space->translation_map; vm_translation_map* map
= &sourceArea->address_space->translation_map;
map->ops->lock(map); map->ops->lock(map);
addr_t physicalAddress; addr_t physicalAddress;
@@ -2544,9 +2550,9 @@ vm_clone_area(team_id team, const char *name, void **address,
static void static void
remove_area_from_address_space(vm_address_space* addressSpace, vm_area* area) remove_area_from_address_space(vm_address_space* addressSpace, vm_area* area)
{ {
vm_area *temp, *last = NULL; vm_area* temp = addressSpace->areas;
vm_area* last = NULL;
temp = addressSpace->areas;
while (temp != NULL) { while (temp != NULL) {
if (area == temp) { if (area == temp) {
if (last != NULL) { if (last != NULL) {
@@ -2666,19 +2672,20 @@ vm_copy_on_write_area(vm_cache* lowerCache)
lowerCache->AddConsumer(upperCache); lowerCache->AddConsumer(upperCache);
// We now need to remap all pages from all of the cache's areas read-only, so that // We now need to remap all pages from all of the cache's areas read-only, so
// a copy will be created on next write access // that a copy will be created on next write access
for (vm_area* tempArea = upperCache->areas; tempArea != NULL; for (vm_area* tempArea = upperCache->areas; tempArea != NULL;
tempArea = tempArea->cache_next) { tempArea = tempArea->cache_next) {
// The area must be readable in the same way it was previously writable // The area must be readable in the same way it was previously writable
uint32 protection = B_KERNEL_READ_AREA; uint32 protection = B_KERNEL_READ_AREA;
if (tempArea->protection & B_READ_AREA) if ((tempArea->protection & B_READ_AREA) != 0)
protection |= B_READ_AREA; protection |= B_READ_AREA;
vm_translation_map* map = &tempArea->address_space->translation_map; vm_translation_map* map = &tempArea->address_space->translation_map;
map->ops->lock(map); map->ops->lock(map);
map->ops->protect(map, tempArea->base, tempArea->base - 1 + tempArea->size, protection); map->ops->protect(map, tempArea->base,
tempArea->base - 1 + tempArea->size, protection);
map->ops->unlock(map); map->ops->unlock(map);
} }
@@ -2777,8 +2784,8 @@ static status_t
vm_set_area_protection(team_id team, area_id areaID, uint32 newProtection, vm_set_area_protection(team_id team, area_id areaID, uint32 newProtection,
bool kernel) bool kernel)
{ {
TRACE(("vm_set_area_protection(team = %#lx, area = %#lx, protection = %#lx)\n", TRACE(("vm_set_area_protection(team = %#lx, area = %#lx, protection = "
team, areaID, newProtection)); "%#lx)\n", team, areaID, newProtection));
if (!arch_vm_supports_protection(newProtection)) if (!arch_vm_supports_protection(newProtection))
return B_NOT_SUPPORTED; return B_NOT_SUPPORTED;
@@ -2818,7 +2825,8 @@ vm_set_area_protection(team_id team, area_id areaID, uint32 newProtection,
status = cache->Commit(cache->page_count * B_PAGE_SIZE); status = cache->Commit(cache->page_count * B_PAGE_SIZE);
// ToDo: we may be able to join with our source cache, if count == 0 // TODO: we may be able to join with our source cache, if
// count == 0
} }
} }
} else if ((area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) == 0 } else if ((area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) == 0
@@ -2923,7 +2931,7 @@ vm_test_map_modification(vm_page *page)
&physicalAddress, &flags); &physicalAddress, &flags);
map->ops->unlock(map); map->ops->unlock(map);
if (flags & PAGE_MODIFIED) if ((flags & PAGE_MODIFIED) != 0)
return true; return true;
} }
@@ -2952,9 +2960,9 @@ vm_test_map_activation(vm_page *page, bool *_modified)
&physicalAddress, &flags); &physicalAddress, &flags);
map->ops->unlock(map); map->ops->unlock(map);
if (flags & PAGE_ACCESSED) if ((flags & PAGE_ACCESSED) != 0)
activation++; activation++;
if (flags & PAGE_MODIFIED) if ((flags & PAGE_MODIFIED) != 0)
modified = true; modified = true;
} }
@@ -3615,7 +3623,8 @@ dump_cache(int argc, char **argv)
kprintf(" consumers:\n"); kprintf(" consumers:\n");
vm_cache* consumer = NULL; vm_cache* consumer = NULL;
while ((consumer = (vm_cache *)list_get_next_item(&cache->consumers, consumer)) != NULL) { while ((consumer = (vm_cache*)list_get_next_item(&cache->consumers,
consumer)) != NULL) {
kprintf("\t%p\n", consumer); kprintf("\t%p\n", consumer);
} }
@@ -3740,8 +3749,9 @@ dump_area_list(int argc, char **argv)
|| (name != NULL && strstr(area->name, name) == NULL)) || (name != NULL && strstr(area->name, name) == NULL))
continue; continue;
kprintf("%p %5lx %p\t%p %4lx\t%4d %s\n", area, area->id, (void *)area->base, kprintf("%p %5lx %p\t%p %4lx\t%4d %s\n", area, area->id,
(void *)area->size, area->protection, area->wiring, area->name); (void*)area->base, (void*)area->size, area->protection, area->wiring,
area->name);
} }
hash_close(sAreaHash, &iter, false); hash_close(sAreaHash, &iter, false);
return 0; return 0;
@@ -3761,7 +3771,8 @@ status_t
vm_delete_areas(struct vm_address_space* addressSpace) vm_delete_areas(struct vm_address_space* addressSpace)
{ {
vm_area* area; vm_area* area;
vm_area *next, *last = NULL; vm_area* next;
vm_area* last = NULL;
TRACE(("vm_delete_areas: called on address space 0x%lx\n", TRACE(("vm_delete_areas: called on address space 0x%lx\n",
addressSpace->id)); addressSpace->id));
@@ -3815,8 +3826,7 @@ vm_area_for(team_id team, addr_t address)
} }
/*! /*! Frees physical pages that were used during the boot process.
Frees physical pages that were used during the boot process.
*/ */
static void static void
unmap_and_free_physical_pages(vm_translation_map* map, addr_t start, addr_t end) unmap_and_free_physical_pages(vm_translation_map* map, addr_t start, addr_t end)
@@ -3847,7 +3857,8 @@ vm_free_unused_boot_loader_range(addr_t start, addr_t size)
addr_t lastEnd = start; addr_t lastEnd = start;
vm_area* area; vm_area* area;
TRACE(("vm_free_unused_boot_loader_range(): asked to free %p - %p\n", (void *)start, (void *)end)); TRACE(("vm_free_unused_boot_loader_range(): asked to free %p - %p\n",
(void*)start, (void*)end));
// The areas are sorted in virtual address space order, so // The areas are sorted in virtual address space order, so
// we just have to find the holes between them that fall // we just have to find the holes between them that fall
@@ -3855,7 +3866,8 @@ vm_free_unused_boot_loader_range(addr_t start, addr_t size)
map->ops->lock(map); map->ops->lock(map);
for (area = vm_kernel_address_space()->areas; area; area = area->address_space_next) { for (area = vm_kernel_address_space()->areas; area != NULL;
area = area->address_space_next) {
addr_t areaStart = area->base; addr_t areaStart = area->base;
addr_t areaEnd = areaStart + area->size; addr_t areaEnd = areaStart + area->size;
@@ -3870,7 +3882,8 @@ vm_free_unused_boot_loader_range(addr_t start, addr_t size)
if (areaStart > lastEnd) { if (areaStart > lastEnd) {
// this is something we can free // this is something we can free
TRACE(("free boot range: get rid of %p - %p\n", (void *)lastEnd, (void *)areaStart)); TRACE(("free boot range: get rid of %p - %p\n", (void*)lastEnd,
(void*)areaStart));
unmap_and_free_physical_pages(map, lastEnd, areaStart); unmap_and_free_physical_pages(map, lastEnd, areaStart);
} }
@@ -3879,7 +3892,8 @@ vm_free_unused_boot_loader_range(addr_t start, addr_t size)
if (lastEnd < end) { if (lastEnd < end) {
// we can also get rid of some space at the end of the area // we can also get rid of some space at the end of the area
TRACE(("free boot range: also remove %p - %p\n", (void *)lastEnd, (void *)end)); TRACE(("free boot range: also remove %p - %p\n", (void*)lastEnd,
(void*)end));
unmap_and_free_physical_pages(map, lastEnd, end); unmap_and_free_physical_pages(map, lastEnd, end);
} }
@@ -3923,11 +3937,10 @@ create_preloaded_image_areas(struct preloaded_image *image)
} }
/** Frees all previously kernel arguments areas from the kernel_args structure. /*! Frees all previously kernel arguments areas from the kernel_args structure.
* Any boot loader resources contained in that arguments must not be accessed Any boot loader resources contained in that arguments must not be accessed
* anymore past this point. anymore past this point.
*/ */
void void
vm_free_kernel_args(kernel_args* args) vm_free_kernel_args(kernel_args* args)
{ {
@@ -3946,15 +3959,14 @@ vm_free_kernel_args(kernel_args *args)
static void static void
allocate_kernel_args(kernel_args* args) allocate_kernel_args(kernel_args* args)
{ {
uint32 i;
TRACE(("allocate_kernel_args()\n")); TRACE(("allocate_kernel_args()\n"));
for (i = 0; i < args->num_kernel_args_ranges; i++) { for (uint32 i = 0; i < args->num_kernel_args_ranges; i++) {
void* address = (void*)args->kernel_args_range[i].start; void* address = (void*)args->kernel_args_range[i].start;
create_area("_kernel args_", &address, B_EXACT_ADDRESS, args->kernel_args_range[i].size, create_area("_kernel args_", &address, B_EXACT_ADDRESS,
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); args->kernel_args_range[i].size, B_ALREADY_WIRED,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
} }
} }
@@ -3962,11 +3974,9 @@ allocate_kernel_args(kernel_args *args)
static void static void
unreserve_boot_loader_ranges(kernel_args* args) unreserve_boot_loader_ranges(kernel_args* args)
{ {
uint32 i;
TRACE(("unreserve_boot_loader_ranges()\n")); TRACE(("unreserve_boot_loader_ranges()\n"));
for (i = 0; i < args->num_virtual_allocated_ranges; i++) { for (uint32 i = 0; i < args->num_virtual_allocated_ranges; i++) {
vm_unreserve_address_range(vm_kernel_address_space_id(), vm_unreserve_address_range(vm_kernel_address_space_id(),
(void*)args->virtual_allocated_range[i].start, (void*)args->virtual_allocated_range[i].start,
args->virtual_allocated_range[i].size); args->virtual_allocated_range[i].size);
@@ -3977,11 +3987,9 @@ unreserve_boot_loader_ranges(kernel_args *args)
static void static void
reserve_boot_loader_ranges(kernel_args* args) reserve_boot_loader_ranges(kernel_args* args)
{ {
uint32 i;
TRACE(("reserve_boot_loader_ranges()\n")); TRACE(("reserve_boot_loader_ranges()\n"));
for (i = 0; i < args->num_virtual_allocated_ranges; i++) { for (uint32 i = 0; i < args->num_virtual_allocated_ranges; i++) {
void* address = (void*)args->virtual_allocated_range[i].start; void* address = (void*)args->virtual_allocated_range[i].start;
// If the address is no kernel address, we just skip it. The // If the address is no kernel address, we just skip it. The
@@ -3992,8 +4000,8 @@ reserve_boot_loader_ranges(kernel_args *args)
continue; continue;
} }
status_t status = vm_reserve_address_range(vm_kernel_address_space_id(), &address, status_t status = vm_reserve_address_range(vm_kernel_address_space_id(),
B_EXACT_ADDRESS, args->virtual_allocated_range[i].size, 0); &address, B_EXACT_ADDRESS, args->virtual_allocated_range[i].size, 0);
if (status < B_OK) if (status < B_OK)
panic("could not reserve boot loader ranges\n"); panic("could not reserve boot loader ranges\n");
} }
@@ -4051,7 +4059,8 @@ out:
static bool static bool
is_page_in_physical_memory_range(kernel_args* args, addr_t address) is_page_in_physical_memory_range(kernel_args* args, addr_t address)
{ {
// TODO: horrible brute-force method of determining if the page can be allocated // TODO: horrible brute-force method of determining if the page can be
// allocated
for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) { for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) {
if (address >= args->physical_memory_range[i].start if (address >= args->physical_memory_range[i].start
&& address < args->physical_memory_range[i].start && address < args->physical_memory_range[i].start
@@ -4090,8 +4099,7 @@ allocate_early_physical_page(kernel_args *args)
} }
/*! /*! This one uses the kernel_args' physical and virtual memory ranges to
This one uses the kernel_args' physical and virtual memory ranges to
allocate some pages before the VM is completely up. allocate some pages before the VM is completely up.
*/ */
addr_t addr_t
@@ -4122,6 +4130,7 @@ vm_allocate_early(kernel_args *args, size_t virtualSize, size_t physicalSize,
} }
/*! The main entrance point to initialize the VM. */
status_t status_t
vm_init(kernel_args* args) vm_init(kernel_args* args)
{ {
@@ -4176,7 +4185,8 @@ vm_init(kernel_args *args)
vm_address_space_init(); vm_address_space_init();
reserve_boot_loader_ranges(args); reserve_boot_loader_ranges(args);
// do any further initialization that the architecture dependant layers may need now // Do any further initialization that the architecture dependant layers may
// need now
arch_vm_translation_map_init_post_area(args); arch_vm_translation_map_init_post_area(args);
arch_vm_init_post_area(args); arch_vm_init_post_area(args);
vm_page_init_post_area(args); vm_page_init_post_area(args);
@@ -4220,7 +4230,8 @@ vm_init(kernel_args *args)
// add some debugger commands // add some debugger commands
add_debugger_command("areas", &dump_area_list, "Dump a list of all areas"); add_debugger_command("areas", &dump_area_list, "Dump a list of all areas");
add_debugger_command("area", &dump_area, "Dump info about a particular area"); add_debugger_command("area", &dump_area,
"Dump info about a particular area");
add_debugger_command("cache", &dump_cache, "Dump vm_cache"); add_debugger_command("cache", &dump_cache, "Dump vm_cache");
add_debugger_command("cache_tree", &dump_cache_tree, "Dump vm_cache tree"); add_debugger_command("cache_tree", &dump_cache_tree, "Dump vm_cache tree");
#if DEBUG_CACHE_LIST #if DEBUG_CACHE_LIST
@@ -4231,7 +4242,8 @@ vm_init(kernel_args *args)
"used pages or, if \"-c\" is specified, by size of committed memory.\n", "used pages or, if \"-c\" is specified, by size of committed memory.\n",
0); 0);
#endif #endif
add_debugger_command("avail", &dump_available_memory, "Dump available memory"); add_debugger_command("avail", &dump_available_memory,
"Dump available memory");
add_debugger_command("dl", &display_mem, "dump memory long words (64-bit)"); add_debugger_command("dl", &display_mem, "dump memory long words (64-bit)");
add_debugger_command("dw", &display_mem, "dump memory words (32-bit)"); add_debugger_command("dw", &display_mem, "dump memory words (32-bit)");
add_debugger_command("ds", &display_mem, "dump memory shorts (16-bit)"); add_debugger_command("ds", &display_mem, "dump memory shorts (16-bit)");
@@ -4247,13 +4259,14 @@ vm_init(kernel_args *args)
status_t status_t
vm_init_post_sem(kernel_args* args) vm_init_post_sem(kernel_args* args)
{ {
// This frees all unused boot loader resources and makes its space available again // This frees all unused boot loader resources and makes its space available
// again
arch_vm_init_end(args); arch_vm_init_end(args);
unreserve_boot_loader_ranges(args); unreserve_boot_loader_ranges(args);
// fill in all of the semaphores that were not allocated before // fill in all of the semaphores that were not allocated before
// since we're still single threaded and only the kernel address space exists, // since we're still single threaded and only the kernel address space
// it isn't that hard to find all of the ones we need to create // exists, it isn't that hard to find all of the ones we need to create
arch_vm_translation_map_init_post_sem(args); arch_vm_translation_map_init_post_sem(args);
vm_address_space_init_post_sem(); vm_address_space_init_post_sem();
@@ -4346,7 +4359,8 @@ vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite, bool isUser,
status = vm_soft_fault(addressSpace, pageAddress, isWrite, isUser); status = vm_soft_fault(addressSpace, pageAddress, isWrite, isUser);
if (status < B_OK) { if (status < B_OK) {
dprintf("vm_page_fault: vm_soft_fault returned error '%s' on fault at 0x%lx, ip 0x%lx, write %d, user %d, thread 0x%lx\n", dprintf("vm_page_fault: vm_soft_fault returned error '%s' on fault at "
"0x%lx, ip 0x%lx, write %d, user %d, thread 0x%lx\n",
strerror(status), address, faultAddress, isWrite, isUser, strerror(status), address, faultAddress, isWrite, isUser,
thread_get_current_thread_id()); thread_get_current_thread_id());
if (!isUser) { if (!isUser) {
@@ -4358,8 +4372,8 @@ vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite, bool isUser,
*newIP = thread->fault_handler; *newIP = thread->fault_handler;
} else { } else {
// unhandled page fault in the kernel // unhandled page fault in the kernel
panic("vm_page_fault: unhandled page fault in kernel space at 0x%lx, ip 0x%lx\n", panic("vm_page_fault: unhandled page fault in kernel space at "
address, faultAddress); "0x%lx, ip 0x%lx\n", address, faultAddress);
} }
} else { } else {
#if 1 #if 1
@@ -4475,8 +4489,7 @@ fault_acquire_locked_source(vm_cache *cache, vm_cache **_source)
} }
/*! /*! Inserts a busy dummy page into a cache, and makes sure the cache won't go
Inserts a busy dummy page into a cache, and makes sure the cache won't go
away by grabbing a reference to it. away by grabbing a reference to it.
*/ */
static inline void static inline void
@@ -4490,8 +4503,7 @@ fault_insert_dummy_page(vm_cache *cache, vm_dummy_page &dummyPage,
} }
/*! /*! Removes the busy dummy page from a cache, and releases its reference to
Removes the busy dummy page from a cache, and releases its reference to
the cache. the cache.
*/ */
static inline void static inline void
@@ -4514,13 +4526,13 @@ fault_remove_dummy_page(vm_dummy_page &dummyPage, bool isLocked)
} }
/*! /*! Finds a page at the specified \a cacheOffset in either the \a topCacheRef
Finds a page at the specified \a cacheOffset in either the \a topCacheRef
or in its source chain. Will also page in a missing page in case there is or in its source chain. Will also page in a missing page in case there is
a cache that has the page. a cache that has the page.
If it couldn't find a page, it will return the vm_cache that should get it, If it couldn't find a page, it will return the vm_cache that should get it,
otherwise, it will return the vm_cache that contains the cache. otherwise, it will return the vm_cache that contains the cache.
It always grabs a reference to the vm_cache that it returns, and also locks it. It always grabs a reference to the vm_cache that it returns, and also locks
it.
*/ */
static inline status_t static inline status_t
fault_find_page(vm_translation_map* map, vm_cache* topCache, fault_find_page(vm_translation_map* map, vm_cache* topCache,
@@ -4620,7 +4632,8 @@ fault_find_page(vm_translation_map *map, vm_cache *topCache,
if (status < B_OK) if (status < B_OK)
nextCache = NULL; nextCache = NULL;
// at this point, we still hold a ref to this cache (through lastCacheRef) // at this point, we still hold a ref to this cache
// (through lastCacheRef)
cache = nextCache; cache = nextCache;
} }
@@ -4663,8 +4676,7 @@ fault_find_page(vm_translation_map *map, vm_cache *topCache,
} }
/*! /*! Returns the page that should be mapped into the area that got the fault.
Returns the page that should be mapped into the area that got the fault.
It returns the owner of the page in \a sourceCache - it keeps a reference It returns the owner of the page in \a sourceCache - it keeps a reference
to it, and has also locked it on exit. to it, and has also locked it on exit.
*/ */
@@ -4701,9 +4713,11 @@ fault_get_page(vm_translation_map *map, vm_cache *topCache, off_t cacheOffset,
// we still haven't found a page, so we allocate a clean one // we still haven't found a page, so we allocate a clean one
page = vm_page_allocate_page(PAGE_STATE_CLEAR, true); page = vm_page_allocate_page(PAGE_STATE_CLEAR, true);
FTRACE(("vm_soft_fault: just allocated page 0x%lx\n", page->physical_page_number)); FTRACE(("vm_soft_fault: just allocated page 0x%lx\n",
page->physical_page_number));
// Insert the new page into our cache, and replace it with the dummy page if necessary // Insert the new page into our cache, and replace it with the dummy page
// if necessary
// If we inserted a dummy page into this cache (i.e. if it is the top // If we inserted a dummy page into this cache (i.e. if it is the top
// cache), we have to remove it now // cache), we have to remove it now
@@ -4750,15 +4764,10 @@ fault_get_page(vm_translation_map *map, vm_cache *topCache, off_t cacheOffset,
// for write faults. // for write faults.
vm_page* sourcePage = page; vm_page* sourcePage = page;
// ToDo: if memory is low, it might be a good idea to steal the page // TODO: if memory is low, it might be a good idea to steal the page
// from our source cache - if possible, that is // from our source cache - if possible, that is
FTRACE(("get new page, copy it, and put it into the topmost cache\n")); FTRACE(("get new page, copy it, and put it into the topmost cache\n"));
page = vm_page_allocate_page(PAGE_STATE_FREE, true); page = vm_page_allocate_page(PAGE_STATE_FREE, true);
#if 0
if (cacheOffset == 0x12000)
dprintf("%ld: copy page %p to page %p from cache %p to cache %p\n", find_thread(NULL),
sourcePage, page, sourcePage->cache, topCacheRef->cache);
#endif
// copy the page // copy the page
vm_memcpy_physical_page(page->physical_page_number * B_PAGE_SIZE, vm_memcpy_physical_page(page->physical_page_number * B_PAGE_SIZE,
@@ -4799,7 +4808,8 @@ if (cacheOffset == 0x12000)
// Insert the new page into our cache and remove the dummy page, if // Insert the new page into our cache and remove the dummy page, if
// necessary. // necessary.
// if we inserted a dummy page into this cache, we have to remove it now // if we inserted a dummy page into this cache, we have to remove it
// now
if (dummyPage.state == PAGE_STATE_BUSY) { if (dummyPage.state == PAGE_STATE_BUSY) {
ASSERT_PRINT(dummyPage.cache == topCache, "dummy page: %p\n", ASSERT_PRINT(dummyPage.cache == topCache, "dummy page: %p\n",
&dummyPage); &dummyPage);
@@ -4847,7 +4857,8 @@ vm_soft_fault(vm_address_space *addressSpace, addr_t originalAddress,
// check permissions // check permissions
uint32 protection = get_area_page_protection(area, address); uint32 protection = get_area_page_protection(area, address);
if (isUser && (protection & B_USER_PROTECTION) == 0) { if (isUser && (protection & B_USER_PROTECTION) == 0) {
dprintf("user access on kernel area 0x%lx at %p\n", area->id, (void *)originalAddress); dprintf("user access on kernel area 0x%lx at %p\n", area->id,
(void*)originalAddress);
TPF(PageFaultError(area->id, TPF(PageFaultError(area->id,
VMPageFaultTracing::PAGE_FAULT_ERROR_KERNEL_ONLY)); VMPageFaultTracing::PAGE_FAULT_ERROR_KERNEL_ONLY));
return B_PERMISSION_DENIED; return B_PERMISSION_DENIED;
@@ -4861,7 +4872,8 @@ vm_soft_fault(vm_address_space *addressSpace, addr_t originalAddress,
return B_PERMISSION_DENIED; return B_PERMISSION_DENIED;
} }
// We have the area, it was a valid access, so let's try to resolve the page fault now. // We have the area, it was a valid access, so let's try to resolve the page
// fault now.
// At first, the top most cache from the area is investigated // At first, the top most cache from the area is investigated
vm_cache* topCache = vm_area_get_locked_cache(area); vm_cache* topCache = vm_area_get_locked_cache(area);
@@ -4884,8 +4896,9 @@ vm_soft_fault(vm_address_space *addressSpace, addr_t originalAddress,
topCache->Unlock(); topCache->Unlock();
// The top most cache has no fault handler, so let's see if the cache or its sources // The top most cache has no fault handler, so let's see if the cache or its
// already have the page we're searching for (we're going from top to bottom) // sources already have the page we're searching for (we're going from top to
// bottom)
vm_translation_map* map = &addressSpace->translation_map; vm_translation_map* map = &addressSpace->translation_map;
size_t reservePages = 2 + map->ops->map_max_pages_need(map, size_t reservePages = 2 + map->ops->map_max_pages_need(map,
@@ -4915,18 +4928,21 @@ vm_soft_fault(vm_address_space *addressSpace, addr_t originalAddress,
dummyPage, &pageSource, &copiedPageSource, &page); dummyPage, &pageSource, &copiedPageSource, &page);
if (status == B_OK) { if (status == B_OK) {
// All went fine, all there is left to do is to map the page into the address space // All went fine, all there is left to do is to map the page into the
// address space
TPF(PageFaultDone(area->id, topCache, page->cache, page)); TPF(PageFaultDone(area->id, topCache, page->cache, page));
// In case this is a copy-on-write page, we need to unmap it from the area now // In case this is a copy-on-write page, we need to unmap it from the
// area now
if (isWrite && page->cache == topCache) if (isWrite && page->cache == topCache)
vm_unmap_pages(area, address, B_PAGE_SIZE, true); vm_unmap_pages(area, address, B_PAGE_SIZE, true);
// TODO: there is currently no mechanism to prevent a page being mapped // TODO: there is currently no mechanism to prevent a page being mapped
// more than once in case of a second page fault! // more than once in case of a second page fault!
// If the page doesn't reside in the area's cache, we need to make sure it's // If the page doesn't reside in the area's cache, we need to make sure
// mapped in read-only, so that we cannot overwrite someone else's data (copy-on-write) // it's mapped in read-only, so that we cannot overwrite someone else's
// data (copy-on-write)
uint32 newProtection = protection; uint32 newProtection = protection;
if (page->cache != topCache && !isWrite) if (page->cache != topCache && !isWrite)
newProtection &= ~(B_WRITE_AREA | B_KERNEL_WRITE_AREA); newProtection &= ~(B_WRITE_AREA | B_KERNEL_WRITE_AREA);
@@ -4943,8 +4959,8 @@ vm_soft_fault(vm_address_space *addressSpace, addr_t originalAddress,
copiedPageSource->ReleaseRef(); copiedPageSource->ReleaseRef();
if (dummyPage.state == PAGE_STATE_BUSY) { if (dummyPage.state == PAGE_STATE_BUSY) {
// We still have the dummy page in the cache - that happens if we didn't need // We still have the dummy page in the cache - that happens if we didn't
// to allocate a new page before, but could use one in another cache // need to allocate a new page before, but could use one in another cache
fault_remove_dummy_page(dummyPage, false); fault_remove_dummy_page(dummyPage, false);
} }
@@ -4963,10 +4979,13 @@ vm_area_lookup(vm_address_space *addressSpace, addr_t address)
// check the areas list first // check the areas list first
area = addressSpace->area_hint; area = addressSpace->area_hint;
if (area && area->base <= address && area->base + (area->size - 1) >= address) if (area != NULL
&& area->base <= address
&& area->base + (area->size - 1) >= address)
goto found; goto found;
for (area = addressSpace->areas; area != NULL; area = area->address_space_next) { for (area = addressSpace->areas; area != NULL;
area = area->address_space_next) {
if (area->id == RESERVED_AREA_ID) if (area->id == RESERVED_AREA_ID)
continue; continue;
@@ -5128,13 +5147,12 @@ vm_set_area_memory_type(area_id id, addr_t physicalBase, uint32 type)
} }
/** This function enforces some protection properties: /*! This function enforces some protection properties:
* - if B_WRITE_AREA is set, B_WRITE_KERNEL_AREA is set as well - if B_WRITE_AREA is set, B_WRITE_KERNEL_AREA is set as well
* - if only B_READ_AREA has been set, B_KERNEL_READ_AREA is also set - if only B_READ_AREA has been set, B_KERNEL_READ_AREA is also set
* - if no protection is specified, it defaults to B_KERNEL_READ_AREA - if no protection is specified, it defaults to B_KERNEL_READ_AREA
* and B_KERNEL_WRITE_AREA. and B_KERNEL_WRITE_AREA.
*/ */
static void static void
fix_protection(uint32* protection) fix_protection(uint32* protection)
{ {
@@ -5161,7 +5179,7 @@ fill_area_info(struct vm_area *area, area_info *info, size_t size)
info->copy_count = 0; info->copy_count = 0;
info->in_count = 0; info->in_count = 0;
info->out_count = 0; info->out_count = 0;
// ToDo: retrieve real values here! // TODO: retrieve real values here!
vm_cache* cache = vm_area_get_locked_cache(area); vm_cache* cache = vm_area_get_locked_cache(area);
@@ -5244,10 +5262,12 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
if (next != NULL && next->base <= (current->base + newSize)) { if (next != NULL && next->base <= (current->base + newSize)) {
// If the area was created inside a reserved area, it can // If the area was created inside a reserved area, it can
// also be resized in that area // also be resized in that area
// ToDo: if there is free space after the reserved area, it could be used as well... // TODO: if there is free space after the reserved area, it could
// be used as well...
if (next->id == RESERVED_AREA_ID if (next->id == RESERVED_AREA_ID
&& next->cache_offset <= current->base && next->cache_offset <= current->base
&& next->base - 1 + next->size >= current->base - 1 + newSize) && next->base - 1 + next->size
>= current->base - 1 + newSize)
continue; continue;
return B_ERROR; return B_ERROR;
@@ -5290,7 +5310,8 @@ vm_resize_area(area_id areaID, size_t newSize, bool kernel)
current->size = newSize; current->size = newSize;
// we also need to unmap all pages beyond the new size, if the area has shrinked // We also need to unmap all pages beyond the new size, if the area has
// shrinked
if (newSize < oldSize) { if (newSize < oldSize) {
vm_unmap_pages(current, current->base + newSize, oldSize - newSize, vm_unmap_pages(current, current->base + newSize, oldSize - newSize,
false); false);
@@ -5354,34 +5375,38 @@ vm_memcpy_physical_page(addr_t to, addr_t from)
status_t status_t
user_memcpy(void* to, const void* from, size_t size) user_memcpy(void* to, const void* from, size_t size)
{ {
if (arch_cpu_user_memcpy(to, from, size, &thread_get_current_thread()->fault_handler) < B_OK) if (arch_cpu_user_memcpy(to, from, size,
&thread_get_current_thread()->fault_handler) < B_OK)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
return B_OK; return B_OK;
} }
/** \brief Copies at most (\a size - 1) characters from the string in \a from to /*! \brief Copies at most (\a size - 1) characters from the string in \a from to
* the string in \a to, NULL-terminating the result. the string in \a to, NULL-terminating the result.
*
* \param to Pointer to the destination C-string.
* \param from Pointer to the source C-string.
* \param size Size in bytes of the string buffer pointed to by \a to.
*
* \return strlen(\a from).
*/
\param to Pointer to the destination C-string.
\param from Pointer to the source C-string.
\param size Size in bytes of the string buffer pointed to by \a to.
\return strlen(\a from).
*/
ssize_t ssize_t
user_strlcpy(char* to, const char* from, size_t size) user_strlcpy(char* to, const char* from, size_t size)
{ {
return arch_cpu_user_strlcpy(to, from, size, &thread_get_current_thread()->fault_handler); return arch_cpu_user_strlcpy(to, from, size,
&thread_get_current_thread()->fault_handler);
} }
status_t status_t
user_memset(void* s, char c, size_t count) user_memset(void* s, char c, size_t count)
{ {
if (arch_cpu_user_memset(s, c, count, &thread_get_current_thread()->fault_handler) < B_OK) if (arch_cpu_user_memset(s, c, count,
&thread_get_current_thread()->fault_handler) < B_OK)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
return B_OK; return B_OK;
} }
@@ -5448,8 +5473,9 @@ lock_memory_etc(team_id team, void *address, size_t numBytes, uint32 flags)
status = vm_soft_fault(addressSpace, base, (flags & B_READ_DEVICE) != 0, status = vm_soft_fault(addressSpace, base, (flags & B_READ_DEVICE) != 0,
isUser); isUser);
if (status != B_OK) { if (status != B_OK) {
dprintf("lock_memory(address = %p, numBytes = %lu, flags = %lu) failed: %s\n", dprintf("lock_memory(address = %p, numBytes = %lu, flags = %lu) "
(void *)unalignedBase, numBytes, flags, strerror(status)); "failed: %s\n", (void*)unalignedBase, numBytes, flags,
strerror(status));
goto out; goto out;
} }
@@ -5804,12 +5830,11 @@ resize_area(area_id areaID, size_t newSize)
} }
/** Transfers the specified area to a new team. The caller must be the owner /*! Transfers the specified area to a new team. The caller must be the owner
* of the area (not yet enforced but probably should be). of the area (not yet enforced but probably should be).
* This function is currently not exported to the kernel namespace, but is This function is currently not exported to the kernel namespace, but is
* only accessible using the _kern_transfer_area() syscall. only accessible using the _kern_transfer_area() syscall.
*/ */
static area_id static area_id
transfer_area(area_id id, void** _address, uint32 addressSpec, team_id target, transfer_area(area_id id, void** _address, uint32 addressSpec, team_id target,
bool kernel) bool kernel)
@@ -5845,8 +5870,9 @@ map_physical_memory(const char *name, void *physicalAddress, size_t numBytes,
fix_protection(&protection); fix_protection(&protection);
return vm_map_physical_memory(vm_kernel_address_space_id(), name, _virtualAddress, return vm_map_physical_memory(vm_kernel_address_space_id(), name,
addressSpec, numBytes, protection, (addr_t)physicalAddress); _virtualAddress, addressSpec, numBytes, protection,
(addr_t)physicalAddress);
} }
@@ -5875,13 +5901,13 @@ create_area_etc(team_id team, const char *name, void **address,
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 protection) uint32 lock, uint32 protection)
{ {
fix_protection(&protection); fix_protection(&protection);
return vm_create_anonymous_area(vm_kernel_address_space_id(), (char *)name, _address, return vm_create_anonymous_area(vm_kernel_address_space_id(), (char*)name,
addressSpec, size, lock, protection, 0, true); _address, addressSpec, size, lock, protection, 0, true);
} }
@@ -5896,7 +5922,8 @@ delete_area(area_id area)
status_t status_t
_user_reserve_heap_address_range(addr_t* userAddress, uint32 addressSpec, addr_t size) _user_reserve_heap_address_range(addr_t* userAddress, uint32 addressSpec,
addr_t size)
{ {
// filter out some unavailable values (for userland) // filter out some unavailable values (for userland)
switch (addressSpec) { switch (addressSpec) {
@@ -5911,8 +5938,9 @@ _user_reserve_heap_address_range(addr_t* userAddress, uint32 addressSpec, addr_t
|| user_memcpy(&address, userAddress, sizeof(address)) < B_OK) || user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
status_t status = vm_reserve_address_range(vm_current_user_address_space_id(), status_t status = vm_reserve_address_range(
(void **)&address, addressSpec, size, RESERVED_AVOID_BASE); vm_current_user_address_space_id(), (void**)&address, addressSpec, size,
RESERVED_AVOID_BASE);
if (status < B_OK) if (status < B_OK)
return status; return status;
@@ -5978,7 +6006,8 @@ _user_get_next_area_info(team_id team, int32 *userCookie, area_info *userInfo)
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
area_info info; area_info info;
status_t status = _get_next_area_info(team, &cookie, &info, sizeof(area_info)); status_t status = _get_next_area_info(team, &cookie, &info,
sizeof(area_info));
if (status != B_OK) if (status != B_OK)
return status; return status;
@@ -6008,14 +6037,15 @@ _user_set_area_protection(area_id area, uint32 newProtection)
status_t status_t
_user_resize_area(area_id area, size_t newSize) _user_resize_area(area_id area, size_t newSize)
{ {
// ToDo: Since we restrict deleting of areas to those owned by the team, // TODO: Since we restrict deleting of areas to those owned by the team,
// we should also do that for resizing (check other functions, too). // we should also do that for resizing (check other functions, too).
return vm_resize_area(area, newSize, false); return vm_resize_area(area, newSize, false);
} }
area_id area_id
_user_transfer_area(area_id area, void **userAddress, uint32 addressSpec, team_id target) _user_transfer_area(area_id area, void** userAddress, uint32 addressSpec,
team_id target)
{ {
// filter out some unavailable values (for userland) // filter out some unavailable values (for userland)
switch (addressSpec) { switch (addressSpec) {
@@ -6064,8 +6094,9 @@ _user_clone_area(const char *userName, void **userAddress, uint32 addressSpec,
fix_protection(&protection); fix_protection(&protection);
area_id clonedArea = vm_clone_area(vm_current_user_address_space_id(), name, &address, area_id clonedArea = vm_clone_area(vm_current_user_address_space_id(), name,
addressSpec, protection, REGION_NO_PRIVATE_MAP, sourceArea, false); &address, addressSpec, protection, REGION_NO_PRIVATE_MAP, sourceArea,
false);
if (clonedArea < B_OK) if (clonedArea < B_OK)
return clonedArea; return clonedArea;
@@ -6109,7 +6140,8 @@ _user_create_area(const char *userName, void **userAddress, uint32 addressSpec,
area_id area = vm_create_anonymous_area(vm_current_user_address_space_id(), area_id area = vm_create_anonymous_area(vm_current_user_address_space_id(),
(char*)name, &address, addressSpec, size, lock, protection, 0, false); (char*)name, &address, addressSpec, size, lock, protection, 0, false);
if (area >= B_OK && user_memcpy(userAddress, &address, sizeof(address)) < B_OK) { if (area >= B_OK
&& user_memcpy(userAddress, &address, sizeof(address)) < B_OK) {
delete_area(area); delete_area(area);
return B_BAD_ADDRESS; return B_BAD_ADDRESS;
} }
@@ -6123,13 +6155,13 @@ _user_delete_area(area_id area)
{ {
// Unlike the BeOS implementation, you can now only delete areas // Unlike the BeOS implementation, you can now only delete areas
// that you have created yourself from userland. // that you have created yourself from userland.
// The documentation to delete_area() explicetly states that this // The documentation to delete_area() explicitly states that this
// will be restricted in the future, and so it will. // will be restricted in the future, and so it will.
return vm_delete_area(vm_current_user_address_space_id(), area, false); return vm_delete_area(vm_current_user_address_space_id(), area, false);
} }
// ToDo: create a BeOS style call for this! // TODO: create a BeOS style call for this!
area_id area_id
_user_map_file(const char* userName, void** userAddress, int addressSpec, _user_map_file(const char* userName, void** userAddress, int addressSpec,