From ffcdd7f3369cd70b544aadb329c5b0e8e483ddfb Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Sun, 8 Jul 2001 01:18:44 +0000 Subject: [PATCH] Finished device vm_store. Now areas created w/vm_map_physical_memory use the new store. Rearranged some code in the region creation area to make a little more sense. Not totally happy with the layout of the api at this point, but will fix that later. git-svn-id: svn+ssh://newos.org/var/svn/newos/newos@202 c25cc9d1-44fa-0310-b259-ad778cb1d433 --- include/kernel/vm.h | 4 +- include/kernel/vm_cache.h | 2 + include/kernel/vm_store_device.h | 14 ++++++ kernel/vm/vm.c | 97 ++++++++++++++++++---------------------- kernel/vm/vm_cache.c | 29 ++++++++++++ kernel/vm/vm_store_device.c | 33 +++++++++----- 6 files changed, 113 insertions(+), 66 deletions(-) create mode 100644 include/kernel/vm_store_device.h diff --git a/include/kernel/vm.h b/include/kernel/vm.h index 56be468..87a914e 100644 --- a/include/kernel/vm.h +++ b/include/kernel/vm.h @@ -137,8 +137,8 @@ enum { REGION_WIRING_LAZY = 0, REGION_WIRING_WIRED, REGION_WIRING_WIRED_ALREADY, - REGION_WIRING_WIRED_PHYSICAL, - REGION_WIRING_WIRED_CONTIG + REGION_WIRING_WIRED_CONTIG, + REGION_WIRING_WIRED_SPECIAL }; enum { diff --git a/include/kernel/vm_cache.h b/include/kernel/vm_cache.h index 0f7e860..244e2f7 100644 --- a/include/kernel/vm_cache.h +++ b/include/kernel/vm_cache.h @@ -15,6 +15,8 @@ void vm_cache_release_ref(vm_cache_ref *cache_ref); vm_page *vm_cache_lookup_page(vm_cache_ref *cache_ref, off_t page); void vm_cache_insert_page(vm_cache_ref *cache_ref, vm_page *page, off_t offset); void vm_cache_remove_page(vm_cache_ref *cache_ref, vm_page *page); +int vm_cache_insert_region(vm_cache_ref *cache_ref, vm_region *region); +int vm_cache_remove_region(vm_cache_ref *cache_ref, vm_region *region); #endif diff --git a/include/kernel/vm_store_device.h b/include/kernel/vm_store_device.h new file mode 100644 index 0000000..04dcc57 --- /dev/null +++ b/include/kernel/vm_store_device.h @@ -0,0 +1,14 @@ +/* +** Copyright 2001, Travis Geiselbrecht. All rights reserved. +** Distributed under the terms of the NewOS License. +*/ +#ifndef _VM_STORE_DEVICE_H +#define _VM_STORE_DEVICE_H + +#include +#include + +vm_store *vm_store_create_device(); + +#endif + diff --git a/kernel/vm/vm.c b/kernel/vm/vm.c index af5dd83..7ca4df2 100644 --- a/kernel/vm/vm.c +++ b/kernel/vm/vm.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -297,21 +298,26 @@ vm_region *_vm_create_region(vm_address_space *aspace, char *name, void **addres return region; } -static region_id _vm_create_anonymous_region(vm_address_space *aspace, char *name, void **address, int addr_type, - addr size, int wiring, int lock, addr phys_addr) +region_id vm_create_anonymous_region(aspace_id aid, char *name, void **address, int addr_type, + addr size, int wiring, int lock) { vm_region *region; vm_cache *cache; vm_cache_ref *cache_ref; vm_store *store; + vm_address_space *aspace; + + aspace = vm_get_aspace_from_id(aid); + if(aspace == NULL) + return -1; region = _vm_create_region(aspace, name, address, addr_type, size, wiring, lock); if(region == NULL) - return NULL; + return -1; // create a new cache - // null vm_store for this one + // anonymous store for this one store = vm_store_create_anonymous_noswap(); if(store == NULL) panic("vm_create_anonymous_region: vm_create_store_anonymous_noswap returned NULL"); @@ -324,6 +330,7 @@ static region_id _vm_create_anonymous_region(vm_address_space *aspace, char *nam vm_cache_acquire_ref(cache_ref); + vm_cache_insert_region(cache_ref, region); region->cache_ref = cache_ref; region->cache_offset = 0; @@ -373,36 +380,6 @@ static region_id _vm_create_anonymous_region(vm_address_space *aspace, char *nam mutex_unlock(&cache_ref->lock); break; } - case REGION_WIRING_WIRED_PHYSICAL: { - addr va; - unsigned int flags; - int err; - vm_page *page; - off_t offset = 0; - - mutex_lock(&cache_ref->lock); - (*aspace->translation_map.ops->lock)(&aspace->translation_map); - for(va = region->base; va < region->base + region->size; va += PAGE_SIZE, offset += PAGE_SIZE, phys_addr += PAGE_SIZE) { - err = (*aspace->translation_map.ops->map)(&aspace->translation_map, - va, phys_addr, lock); - if(err < 0) { - dprintf("vm_create_anonymous_region: error mapping va 0x%x to pa 0x%x\n", - va, phys_addr); - } - page = vm_page_allocate_specific_page(phys_addr / PAGE_SIZE, PAGE_STATE_FREE); - if(page == NULL) { - // not finding a page structure is not the end of the world - // this may be covering a range of the physical address space - // that is not covered by RAM, such as a device. - continue; - } - vm_page_set_state(page, PAGE_STATE_WIRED); - vm_cache_insert_page(cache_ref, page, offset); - } - (*aspace->translation_map.ops->unlock)(&aspace->translation_map); - mutex_unlock(&cache_ref->lock); - break; - } case REGION_WIRING_WIRED_CONTIG: { addr va; addr phys_addr; @@ -445,31 +422,43 @@ static region_id _vm_create_anonymous_region(vm_address_space *aspace, char *nam return -1; } -region_id vm_create_anonymous_region(aspace_id aid, char *name, void **address, int addr_type, - addr size, int wiring, int lock) -{ - vm_address_space *aspace; - if(wiring == REGION_WIRING_WIRED_PHYSICAL) { - // invalid here - return -1; - } - - aspace = vm_get_aspace_from_id(aid); - if(aspace == NULL) - return -1; - - return _vm_create_anonymous_region(aspace, name, address, addr_type, size, wiring, lock, 0); -} - region_id vm_map_physical_memory(aspace_id aid, char *name, void **address, int addr_type, addr size, int lock, addr phys_addr) { + vm_region *region; + vm_cache *cache; + vm_cache_ref *cache_ref; + vm_store *store; + vm_address_space *aspace = vm_get_aspace_from_id(aid); if(aspace == NULL) return -1; - return _vm_create_anonymous_region(aspace, name, address, addr_type, size, - REGION_WIRING_WIRED_PHYSICAL, lock, phys_addr); + region = _vm_create_region(aspace, name, address, addr_type, size, REGION_WIRING_WIRED_SPECIAL, lock); + if(region == NULL) + return -1; + + // create a new cache + store = vm_store_create_device(phys_addr); + if(store == NULL) + panic("vm_map_physical_memory: vm_store_create_device returned NULL"); + cache = vm_cache_create(store); + if(cache == NULL) + panic("vm_map_physical_memory: vm_cache_create returned NULL"); + cache_ref = vm_cache_ref_create(cache); + if(cache_ref == NULL) + panic("vm_map_physical_memory: vm_cache_ref_create returned NULL"); + + vm_cache_acquire_ref(cache_ref); + + vm_cache_insert_region(cache_ref, region); + region->cache_ref = cache_ref; + region->cache_offset = 0; + + if(region) + return region->id; + else + return -1; } int vm_delete_region(aspace_id aid, region_id rid) @@ -480,7 +469,7 @@ int vm_delete_region(aspace_id aid, region_id rid) if(aspace == NULL) return -1; - dprintf("vm_delete_region: aspace 0x%x, region %d\n", aspace, rid); + dprintf("vm_delete_region: aspace 0x%x, region 0x%x\n", aspace, rid); // remove the region from the global hash table sem_acquire(region_hash_sem, READ_COUNT); @@ -490,6 +479,7 @@ int vm_delete_region(aspace_id aid, region_id rid) if(region == NULL) return -1; + // remove the region from the aspace's virtual map sem_acquire(aspace->virtual_map.sem, WRITE_COUNT); temp = aspace->virtual_map.region_list; while(temp != NULL) { @@ -516,6 +506,7 @@ int vm_delete_region(aspace_id aid, region_id rid) hash_remove(region_table, region); sem_release(region_hash_sem, WRITE_COUNT); + vm_cache_remove_region(region->cache_ref, region); vm_cache_release_ref(region->cache_ref); (*aspace->translation_map.ops->lock)(&aspace->translation_map); diff --git a/kernel/vm/vm_cache.c b/kernel/vm/vm_cache.c index c35e127..524f836 100644 --- a/kernel/vm/vm_cache.c +++ b/kernel/vm/vm_cache.c @@ -9,6 +9,7 @@ #include #include #include +#include #include vm_cache *vm_cache_create(vm_store *store) @@ -40,6 +41,7 @@ vm_cache_ref *vm_cache_ref_create(vm_cache *cache) mutex_init(&ref->lock, "cache_ref_mutex"); ref->region_list = NULL; ref->ref_count = 0; + cache->ref = ref; return ref; } @@ -119,3 +121,30 @@ void vm_cache_remove_page(vm_cache_ref *cache_ref, vm_page *page) } page->cache_ref = NULL; } + +int vm_cache_insert_region(vm_cache_ref *cache_ref, vm_region *region) +{ + mutex_lock(&cache_ref->lock); + + region->cache_next = cache_ref->region_list; + if(region->cache_next) + region->cache_next->cache_prev = region; + region->cache_prev = NULL; + cache_ref->region_list = region; + + mutex_unlock(&cache_ref->lock); +} + +int vm_cache_remove_region(vm_cache_ref *cache_ref, vm_region *region) +{ + mutex_lock(&cache_ref->lock); + + if(region->cache_prev) + region->cache_prev->cache_next = region->cache_next; + if(region->cache_next) + region->cache_next->cache_prev = region->cache_prev; + if(cache_ref->region_list == region) + cache_ref->region_list = region->cache_next; + + mutex_unlock(&cache_ref->lock); +} diff --git a/kernel/vm/vm_store_device.c b/kernel/vm/vm_store_device.c index eeb40e0..fa6f36d 100644 --- a/kernel/vm/vm_store_device.c +++ b/kernel/vm/vm_store_device.c @@ -6,6 +6,7 @@ #include #include #include +#include #include struct device_store_data { @@ -47,23 +48,33 @@ static int device_write(struct vm_store *store, off_t offset, const void *buf, s static int device_fault(struct vm_store *store, struct vm_address_space *aspace, off_t offset) { struct device_store_data *d = (struct device_store_data *)store->data; - addr vaddr, paddr; + vm_cache_ref *cache_ref = store->cache->ref; + vm_region *region; dprintf("device_fault: offset 0x%d + base_addr 0x%x\n", offset, d->base_addr); // figure out which page needs to be mapped where - -// XXX finish - -#if 0 - // simply map in the appropriate page, regardless of vm_page coverage (*aspace->translation_map.ops->lock)(&aspace->translation_map); - (*aspace->translation_map.ops->map)(&aspace->translation_map, address, - page->ppn * PAGE_SIZE, region->lock); - (*aspace->translation_map.ops->unlock)(&aspace->translation_map); -#endif + mutex_lock(&cache_ref->lock); + + // cycle through all of the regions that map this cache and map the page in + for(region = cache_ref->region_list; region != NULL; region = region->cache_next) { + // make sure this page in the cache that was faulted on is covered in this region + if(offset >= region->cache_offset && (offset - region->cache_offset) < region->size) { + dprintf("device_fault: mapping paddr 0x%x to vaddr 0x%x\n", + (addr)(d->base_addr + offset), + (addr)(region->base + (offset - region->cache_offset))); + (*aspace->translation_map.ops->map)(&aspace->translation_map, + region->base + (offset - region->cache_offset), + d->base_addr + offset, region->lock); + } + } - panic("here\n"); + mutex_unlock(&cache_ref->lock); + (*aspace->translation_map.ops->unlock)(&aspace->translation_map); + + dprintf("device_fault: done\n"); + return 0; } -- 2.11.4.GIT