]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/vm/vm_pageout.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / osfmk / vm / vm_pageout.c
index d12bd6f36e0caba1e95ea3b3f31b6ce1f86358bf..a84614ed6d3c144118e85786922d60c0f36b0b5e 100644 (file)
@@ -1071,9 +1071,6 @@ struct flow_control {
         mach_timespec_t        ts;
 };
 
-extern kern_return_t   sysclk_gettime(mach_timespec_t *);
-
-
 void
 vm_pageout_scan(void)
 {
@@ -1359,7 +1356,9 @@ done_with_activepage:
 reset_deadlock_timer:
                                ts.tv_sec = vm_pageout_deadlock_wait / 1000;
                                ts.tv_nsec = (vm_pageout_deadlock_wait % 1000) * 1000 * NSEC_PER_USEC;
-                               sysclk_gettime(&flow_control.ts);
+                               clock_get_system_nanotime(
+                                       &flow_control.ts.tv_sec,
+                                       (uint32_t *) &flow_control.ts.tv_nsec);
                                ADD_MACH_TIMESPEC(&flow_control.ts, &ts);
                                
                                flow_control.state = FCS_DELAYED;
@@ -1368,7 +1367,9 @@ reset_deadlock_timer:
                                break;
                                        
                        case FCS_DELAYED:
-                               sysclk_gettime(&ts);
+                               clock_get_system_nanotime(
+                                       &ts.tv_sec,
+                                       (uint32_t *) &ts.tv_nsec);
 
                                if (CMP_MACH_TIMESPEC(&ts, &flow_control.ts) >= 0) {
                                        /*
@@ -1941,7 +1942,9 @@ vm_pageout_iothread_continue(struct vm_pageout_queue *q)
                            */
 
                           if (!object->pager_initialized)
-                                  vm_object_collapse(object, (vm_object_offset_t)0);
+                                  vm_object_collapse(object,
+                                                     (vm_object_offset_t) 0,
+                                                     TRUE);
                           if (!object->pager_initialized)
                                   vm_object_pager_create(object);
                           if (!object->pager_initialized) {
@@ -2221,6 +2224,7 @@ upl_create(
        upl->size = 0;
        upl->map_object = NULL;
        upl->ref_count = 1;
+       upl->highest_page = 0;
        upl_lock_init(upl);
 #ifdef UPL_DEBUG
        upl->ubc_alias1 = 0;
@@ -2399,7 +2403,7 @@ vm_object_upl_request(
                        *page_list_count = MAX_UPL_TRANSFER;
 
        if((!object->internal) && (object->paging_offset != 0))
-               panic("vm_object_upl_request: vnode object with non-zero paging offset\n");
+               panic("vm_object_upl_request: external object with non-zero paging offset\n");
 
        if((cntrl_flags & UPL_COPYOUT_FROM) && (upl_ptr == NULL)) {
                return KERN_SUCCESS;
@@ -2507,6 +2511,7 @@ vm_object_upl_request(
                                   (offset + object->shadow_offset)>>PAGE_SHIFT;
                                user_page_list[0].device = TRUE;
                        }
+                       upl->highest_page = (offset + object->shadow_offset + size - 1)>>PAGE_SHIFT;
 
                        if(page_list_count != NULL) {
                                if (upl->flags & UPL_INTERNAL) {
@@ -2819,6 +2824,9 @@ check_busy:
                                        }
                                }
 
+                               if (dst_page->phys_page > upl->highest_page)
+                                       upl->highest_page = dst_page->phys_page;
+
                                if(user_page_list) {
                                        user_page_list[entry].phys_addr
                                                = dst_page->phys_page;
@@ -3131,6 +3139,10 @@ check_busy:
                                dst_page->precious = 
                                        (cntrl_flags & UPL_PRECIOUS) 
                                                        ? TRUE : FALSE;
+
+                               if (dst_page->phys_page > upl->highest_page)
+                                       upl->highest_page = dst_page->phys_page;
+
                                if(user_page_list) {
                                        user_page_list[entry].phys_addr
                                                = dst_page->phys_page;
@@ -3239,7 +3251,7 @@ vm_fault_list_request(
        int                     page_list_count,
        int                     cntrl_flags)
 {
-       int                     local_list_count;
+       unsigned int            local_list_count;
        upl_page_info_t         *user_page_list;
        kern_return_t           kr;
 
@@ -4698,6 +4710,21 @@ vm_object_iopl_request(
                 */
                return KERN_INVALID_VALUE;
        }
+       if (vm_lopage_poolsize == 0)
+               cntrl_flags &= ~UPL_NEED_32BIT_ADDR;
+
+       if (cntrl_flags & UPL_NEED_32BIT_ADDR) {
+               if ( (cntrl_flags & (UPL_SET_IO_WIRE | UPL_SET_LITE)) != (UPL_SET_IO_WIRE | UPL_SET_LITE))
+                       return KERN_INVALID_VALUE;
+
+               if (object->phys_contiguous) {
+                       if ((offset + object->shadow_offset) >= (vm_object_offset_t)max_valid_dma_address)
+                               return KERN_INVALID_ADDRESS;
+                         
+                       if (((offset + object->shadow_offset) + size) >= (vm_object_offset_t)max_valid_dma_address)
+                               return KERN_INVALID_ADDRESS;
+               }
+       }
 
        if (cntrl_flags & UPL_ENCRYPT) {
                /*
@@ -4730,7 +4757,7 @@ vm_object_iopl_request(
                return KERN_INVALID_ARGUMENT;
 
        if((!object->internal) && (object->paging_offset != 0))
-               panic("vm_object_upl_request: vnode object with non-zero paging offset\n");
+               panic("vm_object_upl_request: external object with non-zero paging offset\n");
 
        if(object->phys_contiguous) {
                /* No paging operations are possible against this memory */
@@ -4798,6 +4825,7 @@ vm_object_iopl_request(
                                  (offset + object->shadow_offset)>>PAGE_SHIFT;
                                user_page_list[0].device = TRUE;
                        }
+                       upl->highest_page = (offset + object->shadow_offset + size - 1)>>PAGE_SHIFT;
 
                        if(page_list_count != NULL) {
                                if (upl->flags & UPL_INTERNAL) {
@@ -4967,24 +4995,75 @@ vm_object_iopl_request(
                                ret = (error_code ? error_code:
                                        KERN_MEMORY_ERROR);
                                vm_object_lock(object);
-                               for(; offset < dst_offset;
-                                               offset += PAGE_SIZE) {
-                                  dst_page = vm_page_lookup(
-                                               object, offset);
-                                  if(dst_page == VM_PAGE_NULL)
-                                       panic("vm_object_iopl_request: Wired pages missing. \n");
-                                  vm_page_lock_queues();
-                                  vm_page_unwire(dst_page);
-                                  vm_page_unlock_queues();
-                                  VM_STAT(reactivations++);
-                               }
-                               vm_object_unlock(object);
-                               upl_destroy(upl);
-                               return ret;
+
+                               goto return_err;
                        }
                   } while ((result != VM_FAULT_SUCCESS) 
                                || (result == VM_FAULT_INTERRUPTED));
                }
+
+               if ( (cntrl_flags & UPL_NEED_32BIT_ADDR) &&
+                    dst_page->phys_page >= (max_valid_dma_address >> PAGE_SHIFT) ) {
+                       vm_page_t       low_page;
+                       int             refmod;
+
+                       /*
+                        * support devices that can't DMA above 32 bits
+                        * by substituting pages from a pool of low address
+                        * memory for any pages we find above the 4G mark
+                        * can't substitute if the page is already wired because
+                        * we don't know whether that physical address has been
+                        * handed out to some other 64 bit capable DMA device to use
+                        */
+                       if (dst_page->wire_count) {
+                               ret = KERN_PROTECTION_FAILURE;
+                               goto return_err;
+                       }
+                       if (delayed_unlock) {
+                               delayed_unlock = 0;
+                               vm_page_unlock_queues();
+                       }
+                       low_page = vm_page_grablo();
+
+                       if (low_page == VM_PAGE_NULL) {
+                               ret = KERN_RESOURCE_SHORTAGE;
+                               goto return_err;
+                       }
+                       /*
+                        * from here until the vm_page_replace completes
+                        * we musn't drop the object lock... we don't
+                        * want anyone refaulting this page in and using
+                        * it after we disconnect it... we want the fault
+                        * to find the new page being substituted.
+                        */
+                       refmod = pmap_disconnect(dst_page->phys_page);
+
+                       vm_page_copy(dst_page, low_page);
+                       
+                       low_page->reference = dst_page->reference;
+                       low_page->dirty     = dst_page->dirty;
+
+                       if (refmod & VM_MEM_REFERENCED)
+                               low_page->reference = TRUE;
+                       if (refmod & VM_MEM_MODIFIED)
+                               low_page->dirty = TRUE;
+
+                       vm_page_lock_queues();
+                       vm_page_replace(low_page, object, dst_offset);
+                       /*
+                        * keep the queue lock since we're going to 
+                        * need it immediately
+                        */
+                       delayed_unlock = 1;
+
+                       dst_page = low_page;
+                       /*
+                        * vm_page_grablo returned the page marked
+                        * BUSY... we don't need a PAGE_WAKEUP_DONE
+                        * here, because we've never dropped the object lock
+                        */
+                       dst_page->busy = FALSE;
+               }
                if (delayed_unlock == 0)
                        vm_page_lock_queues();
                vm_page_wire(dst_page);
@@ -5030,6 +5109,9 @@ vm_object_iopl_request(
                                dst_page->dirty = TRUE;
                        alias_page = NULL;
 
+                       if (dst_page->phys_page > upl->highest_page)
+                               upl->highest_page = dst_page->phys_page;
+
                        if (user_page_list) {
                                user_page_list[entry].phys_addr
                                        = dst_page->phys_page;
@@ -5082,8 +5164,30 @@ vm_object_iopl_request(
        }
 
        return KERN_SUCCESS;
+
+
+return_err:
+       if (delayed_unlock)
+               vm_page_unlock_queues();
+
+       for (; offset < dst_offset; offset += PAGE_SIZE) {
+               dst_page = vm_page_lookup(object, offset);
+
+               if (dst_page == VM_PAGE_NULL)
+                       panic("vm_object_iopl_request: Wired pages missing. \n");
+               vm_page_lock_queues();
+               vm_page_unwire(dst_page);
+               vm_page_unlock_queues();
+               VM_STAT(reactivations++);
+       }
+       vm_object_paging_end(object);
+       vm_object_unlock(object);
+       upl_destroy(upl);
+
+       return ret;
 }
 
+
 kern_return_t
 upl_transpose(
        upl_t           upl1,
@@ -5259,6 +5363,7 @@ vm_paging_map_object(
                                               &page_map_offset,
                                               VM_PAGING_NUM_PAGES * PAGE_SIZE,
                                               0,
+                                              0,
                                               &map_entry);
                        if (kr != KERN_SUCCESS) {
                                panic("vm_paging_map_object: "
@@ -5428,7 +5533,7 @@ vm_paging_unmap_object(
        int             i;
 #endif /* __ppc__ */
 
-       if ((vm_paging_base_address != 0) &&
+       if ((vm_paging_base_address == 0) &&
            ((start < vm_paging_base_address) ||
             (end > (vm_paging_base_address
                     + (VM_PAGING_NUM_PAGES * PAGE_SIZE))))) {
@@ -5853,7 +5958,7 @@ vm_page_decrypt(
         * be part of a DMA transfer from a driver that expects the memory to
         * be coherent at this point, we have to flush the data cache.
         */
-       pmap_sync_page_data_phys(page->phys_page);
+       pmap_sync_page_attributes_phys(page->phys_page);
        /*
         * Since the page is not mapped yet, some code might assume that it
         * doesn't need to invalidate the instruction cache when writing to
@@ -5976,18 +6081,16 @@ upl_get_internal_pagelist_offset(void)
        return sizeof(struct upl);
 }
 
-void
-upl_set_dirty(
-       upl_t   upl)
-{
-       upl->flags |= UPL_CLEAR_DIRTY;
-}
-
 void
 upl_clear_dirty(
-       upl_t   upl)
+       upl_t           upl,
+       boolean_t       value)
 {
-       upl->flags &= ~UPL_CLEAR_DIRTY;
+       if (value) {
+               upl->flags |= UPL_CLEAR_DIRTY;
+       } else {
+               upl->flags &= ~UPL_CLEAR_DIRTY;
+       }
 }
 
 
@@ -6082,6 +6185,12 @@ vm_countdirtypages(void)
 }
 #endif /* MACH_BSD */
 
+ppnum_t upl_get_highest_page(
+       upl_t                   upl)
+{
+       return upl->highest_page;
+}
+
 #ifdef UPL_DEBUG
 kern_return_t  upl_ubc_alias_set(upl_t upl, unsigned int alias1, unsigned int alias2)
 {