Changeset 25450

Show
Ignore:
Timestamp:
05/11/08 11:02:13 (5 days ago)
Author:
bonefish
Message:
Added new private area protection flag B_KERNEL_AREA, which prevents all
changes to the area (delete, resize, clone) from userland.
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • haiku/trunk/headers/private/kernel/vm.h

    r24964 r25450  
    4545        | B_KERNEL_STACK_AREA) 
    4646 
     47// TODO: These aren't really a protection flags, but since the "protection" 
     48//      field is the only flag field, we currently use it for this. 
     49//      A cleaner approach would be appreciated - maybe just an official generic 
     50//      flags region in the protection field. 
    4751#define B_OVERCOMMITTING_AREA   0x1000 
    4852#define B_SHARED_AREA                   0x2000 
    49         // TODO: These aren't really a protection flags, but since the "protection" 
    50         //      field is the only flag field, we currently use it for this. 
    51         //      A cleaner approach would be appreciated - maybe just an official generic 
    52         //      flags region in the protection field. 
    53  
     53#define B_KERNEL_AREA                   0x4000 
     54        // Usable from userland according to its protection flags, but the area 
     55        // itself is not deletable, resizable, etc from userland. 
    5456 
    5557#define B_USER_AREA_FLAGS               (B_USER_PROTECTION) 
     
    111113area_id vm_create_anonymous_area(team_id team, const char *name, void **address, 
    112114                        uint32 addressSpec, addr_t size, uint32 wiring, uint32 protection, 
    113                         bool unmapAddressRange); 
     115                        bool unmapAddressRange, bool kernel); 
    114116area_id vm_map_physical_memory(team_id team, const char *name, void **address, 
    115117                        uint32 addressSpec, addr_t size, uint32 protection, addr_t phys_addr); 
     
    125127area_id vm_clone_area(team_id team, const char *name, void **address, 
    126128                        uint32 addressSpec, uint32 protection, uint32 mapping, 
    127                         area_id sourceArea); 
    128 status_t vm_delete_area(team_id teamID, area_id areaID); 
     129                        area_id sourceArea, bool kernel); 
     130status_t vm_delete_area(team_id teamID, area_id areaID, bool kernel); 
    129131status_t vm_create_vnode_cache(struct vnode *vnode, struct vm_cache **_cache); 
    130132struct vm_area *vm_area_lookup(struct vm_address_space *addressSpace, 
  • haiku/trunk/src/system/kernel/vm/vm.cpp

    r25399 r25450  
    11951195*/ 
    11961196static status_t 
    1197 unmap_address_range(vm_address_space *addressSpace, addr_t address, addr_t size) 
     1197unmap_address_range(vm_address_space *addressSpace, addr_t address, addr_t size, 
     1198        bool kernel) 
    11981199{ 
    11991200        // TODO: Support deleting partial areas! 
     
    12111212                return B_UNSUPPORTED; 
    12121213 
    1213         // all areas (if any) are fully covered; let's delete them 
     1214        // all areas (if any) are fully covered; we can delete them, 
     1215        // but first we need to check, whether the caller is allowed to do that 
     1216        if (!kernel) { 
     1217                area = addressSpace->areas; 
     1218                while (area != NULL) { 
     1219                        vm_area* nextArea = area->address_space_next; 
     1220         
     1221                        if (area->id != RESERVED_AREA_ID) { 
     1222                                if (area->base >= address && area->base < lastAddress) { 
     1223                                        if ((area->protection & B_KERNEL_AREA) != 0) 
     1224                                                return B_NOT_ALLOWED; 
     1225                                } 
     1226                        } 
     1227         
     1228                        area = nextArea; 
     1229                } 
     1230        } 
     1231 
    12141232        area = addressSpace->areas; 
    12151233        while (area != NULL) { 
     
    12361254        void **_virtualAddress, off_t offset, addr_t size, uint32 addressSpec, 
    12371255        int wiring, int protection, int mapping, vm_area **_area, 
    1238         const char *areaName, bool unmapAddressRange
     1256        const char *areaName, bool unmapAddressRange, bool kernel
    12391257{ 
    12401258        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", 
     
    12991317        if (addressSpec == B_EXACT_ADDRESS && unmapAddressRange) { 
    13001318                status = unmap_address_range(addressSpace, (addr_t)*_virtualAddress, 
    1301                         size); 
     1319                        size, kernel); 
    13021320                if (status != B_OK) 
    13031321                        goto err2; 
     
    14301448vm_create_anonymous_area(team_id team, const char *name, void **address, 
    14311449        uint32 addressSpec, addr_t size, uint32 wiring, uint32 protection, 
    1432         bool unmapAddressRange
     1450        bool unmapAddressRange, bool kernel
    14331451{ 
    14341452        vm_area *area; 
     
    15341552        status = map_backing_store(addressSpace, cache, address, 0, size, 
    15351553                addressSpec, wiring, protection, REGION_NO_PRIVATE_MAP, &area, name, 
    1536                 unmapAddressRange); 
     1554                unmapAddressRange, kernel); 
    15371555 
    15381556        mutex_unlock(&cache->lock); 
     
    17481766        status_t status = map_backing_store(locker.AddressSpace(), cache, _address, 
    17491767                0, size, addressSpec & ~B_MTR_MASK, B_FULL_LOCK, protection, 
    1750                 REGION_NO_PRIVATE_MAP, &area, name, false); 
     1768                REGION_NO_PRIVATE_MAP, &area, name, false, true); 
    17511769 
    17521770        mutex_unlock(&cache->lock); 
     
    18301848        status = map_backing_store(locker.AddressSpace(), cache, address, 0, size, 
    18311849                addressSpec, 0, B_KERNEL_READ_AREA, REGION_NO_PRIVATE_MAP, &area, name, 
    1832                 false); 
     1850                false, true); 
    18331851 
    18341852        mutex_unlock(&cache->lock); 
     
    18981916        if (fd < 0) { 
    18991917                return vm_create_anonymous_area(team, name, _address, addressSpec, size, 
    1900                         B_NO_LOCK, protection, addressSpec == B_EXACT_ADDRESS); 
     1918                        B_NO_LOCK, protection, addressSpec == B_EXACT_ADDRESS, kernel); 
    19011919        } 
    19021920 
     
    19391957        status = map_backing_store(locker.AddressSpace(), cache, _address, 
    19401958                offset, size, addressSpec, 0, protection, mapping, &area, name, 
    1941                 addressSpec == B_EXACT_ADDRESS); 
     1959                addressSpec == B_EXACT_ADDRESS, kernel); 
    19421960 
    19431961        mutex_unlock(&cache->lock); 
     
    19992017area_id 
    20002018vm_clone_area(team_id team, const char *name, void **address, 
    2001         uint32 addressSpec, uint32 protection, uint32 mapping, area_id sourceID) 
     2019        uint32 addressSpec, uint32 protection, uint32 mapping, area_id sourceID, 
     2020        bool kernel) 
    20022021{ 
    20032022        vm_area *newArea = NULL; 
     
    20222041        if (sourceArea == NULL) 
    20232042                return B_BAD_VALUE; 
     2043 
     2044        if (!kernel && (sourceArea->protection & B_KERNEL_AREA) != 0) 
     2045                return B_NOT_ALLOWED; 
    20242046 
    20252047        vm_cache *cache = vm_area_get_locked_cache(sourceArea); 
     
    20412063                status = map_backing_store(targetAddressSpace, cache, address, 
    20422064                        sourceArea->cache_offset, sourceArea->size, addressSpec, 
    2043                         sourceArea->wiring, protection, mapping, &newArea, name, false); 
     2065                        sourceArea->wiring, protection, mapping, &newArea, name, false, 
     2066                        kernel); 
    20442067        } 
    20452068        if (status == B_OK && mapping != REGION_PRIVATE_MAP) { 
     
    21652188 
    21662189status_t 
    2167 vm_delete_area(team_id team, area_id id
     2190vm_delete_area(team_id team, area_id id, bool kernel
    21682191{ 
    21692192        TRACE(("vm_delete_area(team = 0x%lx, area = 0x%lx)\n", team, id)); 
     
    21742197        if (status < B_OK) 
    21752198                return status; 
     2199 
     2200        if (!kernel && (area->protection & B_KERNEL_AREA) != 0) 
     2201                return B_NOT_ALLOWED; 
    21762202 
    21772203        delete_area(locker.AddressSpace(), area); 
     
    23042330                source->cache_offset, source->size, addressSpec, source->wiring, 
    23052331                protection, sharedArea ? REGION_NO_PRIVATE_MAP : REGION_PRIVATE_MAP, 
    2306                 &target, name, false); 
     2332                &target, name, false, true); 
    23072333        if (status < B_OK) 
    23082334                return status; 
     
    23472373 
    23482374static status_t 
    2349 vm_set_area_protection(team_id team, area_id areaID, uint32 newProtection) 
     2375vm_set_area_protection(team_id team, area_id areaID, uint32 newProtection, 
     2376        bool kernel) 
    23502377{ 
    23512378        TRACE(("vm_set_area_protection(team = %#lx, area = %#lx, protection = %#lx)\n", 
     
    23622389                &cache, true); 
    23632390        AreaCacheLocker cacheLocker(cache);     // already locked 
     2391 
     2392        if (!kernel && (area->protection & B_KERNEL_AREA) != 0) 
     2393                return B_NOT_ALLOWED; 
    23642394 
    23652395        if (area->protection == newProtection) 
     
    45984628 
    45994629 
    4600 //      #pragma mark - kernel public API 
    4601  
    4602  
    4603 status_t 
    4604 user_memcpy(void *to, const void *from, size_t size) 
    4605 
    4606         if (arch_cpu_user_memcpy(to, from, size, &thread_get_current_thread()->fault_handler) < B_OK) 
    4607                 return B_BAD_ADDRESS; 
    4608         return B_OK; 
    4609 
    4610  
    4611  
    4612 /**     \brief Copies at most (\a size - 1) characters from the string in \a from to 
    4613  *      the string in \a to, NULL-terminating the result. 
    4614  * 
    4615  *      \param to Pointer to the destination C-string. 
    4616  *      \param from Pointer to the source C-string. 
    4617  *      \param size Size in bytes of the string buffer pointed to by \a to. 
    4618  * 
    4619  *      \return strlen(\a from). 
    4620  */ 
    4621  
    4622 ssize_t 
    4623 user_strlcpy(char *to, const char *from, size_t size) 
    4624 
    4625         return arch_cpu_user_strlcpy(to, from, size, &thread_get_current_thread()->fault_handler); 
    4626 
    4627  
    4628  
    4629 status_t 
    4630 user_memset(void *s, char c, size_t count) 
    4631 
    4632         if (arch_cpu_user_memset(s, c, count, &thread_get_current_thread()->fault_handler) < B_OK) 
    4633                 return B_BAD_ADDRESS; 
    4634         return B_OK; 
    4635 
    4636  
    4637  
    4638 long 
    4639 lock_memory(void *address, ulong numBytes, ulong flags) 
    4640 
    4641         vm_address_space *addressSpace = NULL; 
    4642         struct vm_translation_map *map; 
    4643         addr_t unalignedBase = (addr_t)address; 
    4644         addr_t end = unalignedBase + numBytes; 
    4645         addr_t base = ROUNDOWN(unalignedBase, B_PAGE_SIZE); 
    4646         bool isUser = IS_USER_ADDRESS(address); 
    4647         bool needsLocking = true; 
    4648  
    4649         if (isUser) 
    4650                 addressSpace = vm_get_current_user_address_space(); 
    4651         else 
    4652                 addressSpace = vm_get_kernel_address_space(); 
    4653         if (addressSpace == NULL) 
    4654                 return B_ERROR; 
    4655  
    4656         // test if we're on an area that allows faults at all 
    4657  
    4658         map = &addressSpace->translation_map; 
    4659  
    4660         status_t status = test_lock_memory(addressSpace, base, needsLocking); 
    4661         if (status < B_OK) 
    4662                 goto out; 
    4663         if (!needsLocking) 
    4664                 goto out; 
    4665  
    4666         for (; base < end; base += B_PAGE_SIZE) { 
    4667                 addr_t physicalAddress; 
    4668                 uint32 protection; 
    4669                 status_t status; 
    4670  
    4671                 map->ops->lock(map); 
    4672                 status = map->ops->query(map, base, &physicalAddress, &protection); 
    4673                 map->ops->unlock(map); 
    4674  
    4675                 if (status < B_OK) 
    4676                         goto out; 
    4677  
    4678                 if ((protection & PAGE_PRESENT) != 0) { 
    4679                         // if B_READ_DEVICE is set, the caller intents to write to the locked 
    4680                         // memory, so if it hasn't been mapped writable, we'll try the soft 
    4681                         // fault anyway 
    4682                         if ((flags & B_READ_DEVICE) == 0 
    4683                                 || (protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0) { 
    4684                                 // update wiring 
    4685                                 vm_page *page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); 
    4686                                 if (page == NULL) 
    4687                                         panic("couldn't lookup physical page just allocated\n"); 
    4688  
    4689                                 page->wired_count++; 
    4690                                         // TODO: needs to be atomic on all platforms! 
    4691                                 continue; 
    4692                         } 
    4693                 } 
    4694  
    4695                 status = vm_soft_fault(base, (flags & B_READ_DEVICE) != 0, isUser); 
    4696                 if (status != B_OK)     { 
    4697                         dprintf("lock_memory(address = %p, numBytes = %lu, flags = %lu) failed: %s\n", 
    4698                                 (void *)unalignedBase, numBytes, flags, strerror(status)); 
    4699                         goto out; 
    4700                 } 
    4701  
    4702                 map->ops->lock(map); 
    4703                 status = map->ops->query(map, base, &physicalAddress, &protection); 
    4704                 map->ops->unlock(map); 
    4705  
    4706                 if (status < B_OK) 
    4707                         goto out; 
    4708  
    4709                 // update wiring 
    4710                 vm_page *page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); 
    4711                 if (page == NULL) 
    4712                         panic("couldn't lookup physical page"); 
    4713  
    4714                 page->wired_count++; 
    4715                         // TODO: needs to be atomic on all platforms! 
    4716         } 
    4717  
    4718 out: 
    4719         vm_put_address_space(addressSpace); 
    4720         return status; 
    4721 
    4722  
    4723  
    4724 long 
    4725 unlock_memory(void *address, ulong numBytes, ulong flags) 
    4726 
    4727         vm_address_space *addressSpace = NULL; 
    4728         struct vm_translation_map *map; 
    4729         addr_t unalignedBase = (addr_t)address; 
    4730         addr_t end = unalignedBase + numBytes; 
    4731         addr_t base = ROUNDOWN(unalignedBase, B_PAGE_SIZE); 
    4732         bool needsLocking = true; 
    4733  
    4734         if (IS_USER_ADDRESS(address)) 
    4735                 addressSpace = vm_get_current_user_address_space(); 
    4736         else 
    4737                 addressSpace = vm_get_kernel_address_space(); 
    4738         if (addressSpace == NULL) 
    4739                 return B_ERROR; 
    4740  
    4741         map = &addressSpace->translation_map; 
    4742  
    4743         status_t status = test_lock_memory(addressSpace, base, needsLocking); 
    4744         if (status < B_OK) 
    4745                 goto out; 
    4746         if (!needsLocking) 
    4747                 goto out; 
    4748  
    4749         for (; base < end; base += B_PAGE_SIZE) { 
    4750                 map->ops->lock(map); 
    4751  
    4752                 addr_t physicalAddress; 
    4753                 uint32 protection; 
    4754                 status = map->ops->query(map, base, &physicalAddress, 
    4755                         &protection); 
    4756  
    4757                 map->ops->unlock(map); 
    4758  
    4759                 if (status < B_OK) 
    4760                         goto out; 
    4761                 if ((protection & PAGE_PRESENT) == 0) 
    4762                         panic("calling unlock_memory() on unmapped memory!"); 
    4763  
    4764                 // update wiring 
    4765                 vm_page *page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); 
    4766                 if (page == NULL) 
    4767                         panic("couldn't lookup physical page"); 
    4768  
    4769                 page->wired_count--; 
    4770                         // TODO: needs to be atomic on all platforms! 
    4771         } 
    4772  
    4773 out: 
    4774         vm_put_address_space(addressSpace); 
    4775         return status; 
    4776 
    4777  
    4778  
    4779 /** According to the BeBook, this function should always succeed. 
    4780  *      This is no longer the case. 
    4781  */ 
    4782  
    4783 long 
    4784 get_memory_map(const void *address, ulong numBytes, physical_entry *table, 
    4785         long numEntries) 
    4786 
    4787         vm_address_space *addressSpace; 
    4788         addr_t virtualAddress = (addr_t)address; 
    4789         addr_t pageOffset = virtualAddress & (B_PAGE_SIZE - 1); 
    4790         addr_t physicalAddress; 
    4791         status_t status = B_OK; 
    4792         int32 index = -1; 
    4793         addr_t offset = 0; 
    4794         bool interrupts = are_interrupts_enabled(); 
    4795  
    4796         TRACE(("get_memory_map(%p, %lu bytes, %ld entries)\n", address, numBytes, 
    4797                 numEntries)); 
    4798  
    4799         if (numEntries == 0 || numBytes == 0) 
    4800                 return B_BAD_VALUE; 
    4801  
    4802         // in which address space is the address to be found? 
    4803         if (IS_USER_ADDRESS(virtualAddress)) 
    4804                 addressSpace = thread_get_current_thread()->team->address_space; 
    4805         else 
    4806                 addressSpace = vm_kernel_address_space(); 
    4807  
    4808         if (addressSpace == NULL) 
    4809                 return B_ERROR; 
    4810  
    4811         vm_translation_map *map = &addressSpace->translation_map; 
    4812  
    4813         if (interrupts) 
    4814                 map->ops->lock(map); 
    4815  
    4816         while (offset < numBytes) { 
    4817                 addr_t bytes = min_c(numBytes - offset, B_PAGE_SIZE); 
    4818                 uint32 flags; 
    4819  
    4820                 if (interrupts) { 
    4821                         status = map->ops->query(map, (addr_t)address + offset, 
    4822                                 &physicalAddress, &flags); 
    4823                 } else { 
    4824                         status = map->ops->query_interrupt(map, (addr_t)address + offset, 
    4825                                 &physicalAddress, &flags); 
    4826                 } 
    4827                 if (status < B_OK) 
    4828                         break; 
    4829                 if ((flags & PAGE_PRESENT) == 0) { 
    4830                         panic("get_memory_map() called on unmapped memory!"); 
    4831                         return B_BAD_ADDRESS; 
    4832                 } 
    4833  
    4834                 if (index < 0 && pageOffset > 0) { 
    4835                         physicalAddress += pageOffset; 
    4836                         if (bytes > B_PAGE_SIZE - pageOffset) 
    4837                                 bytes = B_PAGE_SIZE - pageOffset; 
    4838                 } 
    4839  
    4840                 // need to switch to the next physical_entry? 
    4841                 if (index < 0 || (addr_t)table[index].address 
    4842                                 != physicalAddress - table[index].size) { 
    4843                         if (++index + 1 > numEntries) { 
    4844                                 // table to small 
    4845                                 status = B_BUFFER_OVERFLOW; 
    4846                                 break; 
    4847                         } 
    4848                         table[index].address = (void *)physicalAddress; 
    4849                         table[index].size = bytes; 
    4850                 } else { 
    4851                         // page does fit in current entry 
    4852                         table[index].size += bytes; 
    4853                 } 
    4854  
    4855                 offset += bytes; 
    4856         } 
    4857  
    4858         if (interrupts) 
    4859                 map->ops->unlock(map); 
    4860  
    4861         // close the entry list 
    4862  
    4863         if (status == B_OK) { 
    4864                 // if it's only one entry, we will silently accept the missing ending 
    4865                 if (numEntries == 1) 
    4866                         return B_OK; 
    4867  
    4868                 if (++index + 1 > numEntries) 
    4869                         return B_BUFFER_OVERFLOW; 
    4870  
    4871                 table[index].address = NULL; 
    4872                 table[index].size = 0; 
    4873         } 
    4874  
    4875         return status; 
    4876 
    4877  
    4878  
    4879 area_id 
    4880 area_for(void *address) 
    4881 
    4882         team_id space; 
    4883  
    4884         if (IS_USER_ADDRESS(address)) { 
    4885                 // we try the user team address space, if any 
    4886                 space = vm_current_user_address_space_id(); 
    4887                 if (space < B_OK) 
    4888                         return space; 
    4889         } else 
    4890                 space = vm_kernel_address_space_id(); 
    4891  
    4892         return vm_area_for(space, (addr_t)address); 
    4893 
    4894  
    4895  
    4896 area_id 
    4897 find_area(const char *name) 
    4898 
    4899         acquire_sem_etc(sAreaHashLock, READ_COUNT, 0, 0); 
    4900         struct hash_iterator iterator; 
    4901         hash_open(sAreaHash, &iterator); 
    4902  
    4903         vm_area *area; 
    4904         area_id id = B_NAME_NOT_FOUND; 
    4905         while ((area = (vm_area *)hash_next(sAreaHash, &iterator)) != NULL) { 
    4906                 if (area->id == RESERVED_AREA_ID) 
    4907                         continue; 
    4908  
    4909                 if (!strcmp(area->name, name)) { 
    4910                         id = area->id; 
    4911                         break; 
    4912                 } 
    4913         } 
    4914  
    4915         hash_close(sAreaHash, &iterator, false); 
    4916         release_sem_etc(sAreaHashLock, READ_COUNT, 0); 
    4917  
    4918         return id; 
    4919 
    4920  
    4921  
    4922 status_t 
    4923 _get_area_info(area_id id, area_info *info, size_t size) 
    4924 
    4925         if (size != sizeof(area_info) || info == NULL) 
    4926                 return B_BAD_VALUE; 
    4927  
    4928         AddressSpaceReadLocker locker; 
    4929         vm_area *area; 
    4930         status_t status = locker.SetFromArea(id, area); 
    4931         if (status != B_OK) 
    4932                 return status; 
    4933  
    4934         fill_area_info(area, info, size); 
    4935         return B_OK; 
    4936 
    4937  
    4938  
    4939 status_t 
    4940 _get_next_area_info(team_id team, int32 *cookie, area_info *info, size_t size) 
    4941 
    4942         addr_t nextBase = *(addr_t *)cookie; 
    4943  
    4944         // we're already through the list 
    4945         if (nextBase == (addr_t)-1) 
    4946                 return B_ENTRY_NOT_FOUND; 
    4947  
    4948         if (team == B_CURRENT_TEAM) 
    4949                 team = team_get_current_team_id(); 
    4950  
    4951         AddressSpaceReadLocker locker(team); 
    4952         if (!locker.IsLocked()) 
    4953                 return B_BAD_TEAM_ID; 
    4954  
    4955         vm_area *area; 
    4956         for (area = locker.AddressSpace()->areas; area != NULL; 
    4957                         area = area->address_space_next) { 
    4958                 if (area->id == RESERVED_AREA_ID) 
    4959                         continue; 
    4960  
    4961                 if (area->base > nextBase) 
    4962                         break; 
    4963         } 
    4964  
    4965         if (area == NULL) { 
    4966                 nextBase = (addr_t)-1; 
    4967                 return B_ENTRY_NOT_FOUND; 
    4968         } 
    4969  
    4970         fill_area_info(area, info, size); 
    4971         *cookie = (int32)(area->base); 
    4972  
    4973         return B_OK; 
    4974 
    4975  
    4976  
    4977 status_t 
    4978 set_area_protection(area_id area, uint32 newProtection) 
    4979 
    4980         fix_protection(&newProtection); 
    4981  
    4982         return vm_set_area_protection(vm_kernel_address_space_id(), area, 
    4983                 newProtection); 
    4984 
    4985  
    4986  
    4987 status_t 
    4988 resize_area(area_id areaID, size_t newSize) 
     4630static status_t 
     4631vm_resize_area(area_id areaID, size_t newSize, bool kernel) 
    49894632{ 
    49904633        // is newSize a multiple of B_PAGE_SIZE? 
     
    50024645                return status; 
    50034646        AreaCacheLocker cacheLocker(cache);     // already locked 
     4647 
     4648        // enforce restrictions 
     4649        if (!kernel) { 
     4650                if ((area->protection & B_KERNEL_AREA) != 0) 
     4651                        return B_NOT_ALLOWED; 
     4652                // TODO: Enforce all restrictions (team, etc.)! 
     4653        } 
    50044654 
    50054655        size_t oldSize = area->size; 
     
    50794729        } 
    50804730 
    5081         // ToDo: we must honour the lock restrictions of this area 
     4731        // TODO: we must honour the lock restrictions of this area 
    50824732        return status; 
     4733} 
     4734 
     4735 
     4736//      #pragma mark - kernel public API 
     4737 
     4738 
     4739status_t 
     4740user_memcpy(void *to, const void *from, size_t size) 
     4741{ 
     4742        if (arch_cpu_user_memcpy(to, from, size, &thread_get_current_thread()->fault_handler) < B_OK) 
     4743                return B_BAD_ADDRESS; 
     4744        return B_OK; 
     4745} 
     4746 
     4747 
     4748/**     \brief Copies at most (\a size - 1) characters from the string in \a from to 
     4749 *      the string in \a to, NULL-terminating the result. 
     4750 * 
     4751 *      \param to Pointer to the destination C-string. 
     4752 *      \param from Pointer to the source C-string. 
     4753 *      \param size Size in bytes of the string buffer pointed to by \a to. 
     4754 * 
     4755 *      \return strlen(\a from). 
     4756 */ 
     4757 
     4758ssize_t 
     4759user_strlcpy(char *to, const char *from, size_t size) 
     4760{ 
     4761        return arch_cpu_user_strlcpy(to, from, size, &thread_get_current_thread()->fault_handler); 
     4762} 
     4763 
     4764 
     4765status_t 
     4766user_memset(void *s, char c, size_t count) 
     4767{ 
     4768        if (arch_cpu_user_memset(s, c, count, &thread_get_current_thread()->fault_handler) < B_OK) 
     4769                return B_BAD_ADDRESS; 
     4770        return B_OK; 
     4771} 
     4772 
     4773 
     4774long 
     4775lock_memory(void *address, ulong numBytes, ulong flags) 
     4776{ 
     4777        vm_address_space *addressSpace = NULL; 
     4778        struct vm_translation_map *map; 
     4779        addr_t unalignedBase = (addr_t)address; 
     4780        addr_t end = unalignedBase + numBytes; 
     4781        addr_t base = ROUNDOWN(unalignedBase, B_PAGE_SIZE); 
     4782        bool isUser = IS_USER_ADDRESS(address); 
     4783        bool needsLocking = true; 
     4784 
     4785        if (isUser) 
     4786                addressSpace = vm_get_current_user_address_space(); 
     4787        else 
     4788                addressSpace = vm_get_kernel_address_space(); 
     4789        if (addressSpace == NULL) 
     4790                return B_ERROR; 
     4791 
     4792        // test if we're on an area that allows faults at all 
     4793 
     4794        map = &addressSpace->translation_map; 
     4795 
     4796        status_t status = test_lock_memory(addressSpace, base, needsLocking); 
     4797        if (status < B_OK) 
     4798                goto out; 
     4799        if (!needsLocking) 
     4800                goto out; 
     4801 
     4802        for (; base < end; base += B_PAGE_SIZE) { 
     4803                addr_t physicalAddress; 
     4804                uint32 protection; 
     4805                status_t status; 
     4806 
     4807                map->ops->lock(map); 
     4808                status = map->ops->query(map, base, &physicalAddress, &protection); 
     4809                map->ops->unlock(map); 
     4810 
     4811                if (status < B_OK) 
     4812                        goto out; 
     4813 
     4814                if ((protection & PAGE_PRESENT) != 0) { 
     4815                        // if B_READ_DEVICE is set, the caller intents to write to the locked 
     4816                        // memory, so if it hasn't been mapped writable, we'll try the soft 
     4817                        // fault anyway 
     4818                        if ((flags & B_READ_DEVICE) == 0 
     4819                                || (protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0) { 
     4820                                // update wiring 
     4821                                vm_page *page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); 
     4822                                if (page == NULL) 
     4823                                        panic("couldn't lookup physical page just allocated\n"); 
     4824 
     4825                                page->wired_count++; 
     4826                                        // TODO: needs to be atomic on all platforms! 
     4827                                continue; 
     4828                        } 
     4829                } 
     4830 
     4831                status = vm_soft_fault(base, (flags & B_READ_DEVICE) != 0, isUser); 
     4832                if (status != B_OK)     { 
     4833                        dprintf("lock_memory(address = %p, numBytes = %lu, flags = %lu) failed: %s\n", 
     4834                                (void *)unalignedBase, numBytes, flags, strerror(status)); 
     4835                        goto out; 
     4836                } 
     4837 
     4838                map->ops->lock(map); 
     4839                status = map->ops->query(map, base, &physicalAddress, &protection); 
     4840                map->ops->unlock(map); 
     4841 
     4842                if (status < B_OK) 
     4843                        goto out; 
     4844 
     4845                // update wiring 
     4846                vm_page *page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); 
     4847                if (page == NULL) 
     4848                        panic("couldn't lookup physical page"); 
     4849 
     4850                page->wired_count++; 
     4851                        // TODO: needs to be atomic on all platforms! 
     4852        } 
     4853 
     4854out: 
     4855        vm_put_address_space(addressSpace); 
     4856        return status; 
     4857} 
     4858 
     4859 
     4860long 
     4861unlock_memory(void *address, ulong numBytes, ulong flags) 
     4862{ 
     4863        vm_address_space *addressSpace = NULL; 
     4864        struct vm_translation_map *map; 
     4865        addr_t unalignedBase = (addr_t)address; 
     4866        addr_t end = unalignedBase + numBytes; 
     4867        addr_t base = ROUNDOWN(unalignedBase, B_PAGE_SIZE); 
     4868        bool needsLocking = true; 
     4869 
     4870        if (IS_USER_ADDRESS(address)) 
     4871                addressSpace = vm_get_current_user_address_space(); 
     4872        else 
     4873                addressSpace = vm_get_kernel_address_space(); 
     4874        if (addressSpace == NULL) 
     4875                return B_ERROR; 
     4876 
     4877        map = &addressSpace->translation_map; 
     4878 
     4879        status_t status = test_lock_memory(addressSpace, base, needsLocking); 
     4880        if (status < B_OK) 
     4881                goto out; 
     4882        if (!needsLocking) 
     4883                goto out; 
     4884 
     4885        for (; base < end; base += B_PAGE_SIZE) { 
     4886                map->ops->lock(map); 
     4887 
     4888                addr_t physicalAddress; 
     4889                uint32 protection; 
     4890                status = map->ops->query(map, base, &physicalAddress, 
     4891                        &protection); 
     4892 
     4893                map->ops->unlock(map); 
     4894 
     4895                if (status < B_OK) 
     4896                        goto out; 
     4897                if ((protection & PAGE_PRESENT) == 0) 
     4898                        panic("calling unlock_memory() on unmapped memory!"); 
     4899 
     4900                // update wiring 
     4901                vm_page *page = vm_lookup_page(physicalAddress / B_PAGE_SIZE); 
     4902                if (page == NULL) 
     4903                        panic("couldn't lookup physical page"); 
     4904 
     4905                page->wired_count--; 
     4906                        // TODO: needs to be atomic on all platforms! 
     4907        } 
     4908 
     4909out: 
     4910        vm_put_address_space(addressSpace); 
     4911        return status; 
     4912} 
     4913 
     4914 
     4915/** According to the BeBook, this function should always succeed. 
     4916 *      This is no longer the case. 
     4917 */ 
     4918 
     4919long 
     4920get_memory_map(const void *address, ulong numBytes, physical_entry *table, 
     4921        long numEntries) 
     4922{ 
     4923        vm_address_space *addressSpace; 
     4924        addr_t virtualAddress = (addr_t)address; 
     4925        addr_t pageOffset = virtualAddress & (B_PAGE_SIZE - 1); 
     4926        addr_t physicalAddress; 
     4927        status_t status = B_OK; 
     4928        int32 index = -1; 
     4929        addr_t offset = 0; 
     4930        bool interrupts = are_interrupts_enabled(); 
     4931 
     4932        TRACE(("get_memory_map(%p, %lu bytes, %ld entries)\n", address, numBytes, 
     4933                numEntries)); 
     4934 
     4935        if (numEntries == 0 || numBytes == 0) 
     4936                return B_BAD_VALUE; 
     4937 
     4938        // in which address space is the address to be found? 
     4939        if (IS_USER_ADDRESS(virtualAddress)) 
     4940                addressSpace = thread_get_current_thread()->team->address_space; 
     4941        else 
     4942                addressSpace = vm_kernel_address_space(); 
     4943 
     4944        if (addressSpace == NULL) 
     4945                return B_ERROR; 
     4946 
     4947        vm_translation_map *map = &addressSpace->translation_map; 
     4948 
     4949        if (interrupts) 
     4950                map->ops->lock(map); 
     4951 
     4952        while (offset < numBytes) { 
     4953                addr_t bytes = min_c(numBytes - offset, B_PAGE_SIZE); 
     4954                uint32 flags; 
     4955 
     4956                if (interrupts) { 
     4957                        status = map->ops->query(map, (addr_t)address + offset, 
     4958                                &physicalAddress, &flags); 
     4959                } else { 
     4960                        status = map->ops->query_interrupt(map, (addr_t)address + offset, 
     4961                                &physicalAddress, &flags); 
     4962                } 
     4963                if (status < B_OK) 
     4964                        break; 
     4965                if ((flags & PAGE_PRESENT) == 0) { 
     4966                        panic("get_memory_map() called on unmapped memory!"); 
     4967                        return B_BAD_ADDRESS; 
     4968                } 
     4969 
     4970                if (index < 0 && pageOffset > 0) { 
     4971                        physicalAddress += pageOffset; 
     4972                        if (bytes > B_PAGE_SIZE - pageOffset) 
     4973                                bytes = B_PAGE_SIZE - pageOffset; 
     4974                } 
     4975 
     4976                // need to switch to the next physical_entry? 
     4977                if (index < 0 || (addr_t)table[index].address 
     4978                                != physicalAddress - table[index].size) { 
     4979                        if (++index + 1 > numEntries) { 
     4980                                // table to small 
     4981                                status = B_BUFFER_OVERFLOW; 
     4982                                break; 
     4983                        } 
     4984                        table[index].address = (void *)physicalAddress; 
     4985                        table[index].size = bytes; 
     4986                } else { 
     4987                        // page does fit in current entry 
     4988                        table[index].size += bytes; 
     4989                } 
     4990 
     4991                offset += bytes; 
     4992        } 
     4993 
     4994        if (interrupts) 
     4995                map->ops->unlock(map); 
     4996 
     4997        // close the entry list 
     4998 
     4999        if (status == B_OK) { 
     5000                // if it's only one entry, we will silently accept the missing ending 
     5001                if (numEntries == 1) 
     5002                        return B_OK; 
     5003 
     5004                if (++index + 1 > numEntries) 
     5005                        return B_BUFFER_OVERFLOW; 
     5006 
     5007                table[index].address = NULL; 
     5008                table[index].size = 0; 
     5009        } 
     5010 
     5011        return status; 
     5012} 
     5013 
     5014 
     5015area_id 
     5016area_for(void *address) 
     5017{ 
     5018        team_id space; 
     5019 
     5020        if (IS_USER_ADDRESS(address)) { 
     5021                // we try the user team address space, if any 
     5022                space = vm_current_user_address_space_id(); 
     5023                if (space < B_OK) 
     5024                        return space; 
     5025        } else 
     5026                space = vm_kernel_address_space_id(); 
     5027 
     5028        return vm_area_for(space, (addr_t)address); 
     5029} 
     5030 
     5031 
     5032area_id 
     5033find_area(const char *name) 
     5034{ 
     5035        acquire_sem_etc(sAreaHashLock, READ_COUNT, 0, 0); 
     5036        struct hash_iterator iterator; 
     5037        hash_open(sAreaHash, &iterator); 
     5038 
     5039        vm_area *area; 
     5040        area_id id = B_NAME_NOT_FOUND; 
     5041        while ((area = (vm_area *)hash_next(sAreaHash, &iterator)) != NULL) { 
     5042                if (area->id == RESERVED_AREA_ID) 
     5043                        continue; 
     5044 
     5045                if (!strcmp(area->name, name)) { 
     5046                        id = area->id; 
     5047                        break; 
     5048                } 
     5049        } 
     5050 
     5051        hash_close(sAreaHash, &iterator, false); 
     5052        release_sem_etc(sAreaHashLock, READ_COUNT, 0); 
     5053 
     5054        return id; 
     5055} 
     5056 
     5057 
     5058status_t 
     5059_get_area_info(area_id id, area_info *info, size_t size) 
     5060{ 
     5061        if (size != sizeof(area_info) || info == NULL) 
     5062                return B_BAD_VALUE; 
     5063 
     5064        AddressSpaceReadLocker locker; 
     5065        vm_area *area; 
     5066        status_t status = locker.SetFromArea(id, area); 
     5067        if (status != B_OK) 
     5068                return status; 
     5069 
     5070        fill_area_info(area, info, size); 
     5071        return B_OK; 
     5072} 
     5073 
     5074 
     5075status_t 
     5076_get_next_area_info(team_id team, int32 *cookie, area_info *info, size_t size) 
     5077{ 
     5078        addr_t nextBase = *(addr_t *)cookie; 
     5079 
     5080        // we're already through the list 
     5081        if (nextBase == (addr_t)-1) 
     5082                return B_ENTRY_NOT_FOUND; 
     5083 
     5084        if (team == B_CURRENT_TEAM) 
     5085                team = team_get_current_team_id(); 
     5086 
     5087        AddressSpaceReadLocker locker(team); 
     5088        if (!locker.IsLocked()) 
     5089                return B_BAD_TEAM_ID; 
     5090 
     5091        vm_area *area; 
     5092        for (area = locker.AddressSpace()->areas; area != NULL; 
     5093                        area = area->address_space_next) { 
     5094                if (area->id == RESERVED_AREA_ID) 
     5095                        continue; 
     5096 
     5097                if (area->base > nextBase) 
     5098