Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/mm/as.c

    r59fb782 rfbcdeb8  
    7979#include <syscall/copy.h>
    8080#include <arch/interrupt.h>
    81 #include <interrupt.h>
    8281
    8382/**
     
    131130        as_arch_init();
    132131       
    133         as_slab = slab_cache_create("as_t", sizeof(as_t), 0,
     132        as_slab = slab_cache_create("as_slab", sizeof(as_t), 0,
    134133            as_constructor, as_destructor, SLAB_CACHE_MAGDEFERRED);
    135134       
     
    286285/** Check area conflicts with other areas.
    287286 *
    288  * @param as      Address space.
    289  * @param addr    Starting virtual address of the area being tested.
    290  * @param count   Number of pages in the area being tested.
    291  * @param guarded True if the area being tested is protected by guard pages.
    292  * @param avoid   Do not touch this area.
     287 * @param as    Address space.
     288 * @param addr  Starting virtual address of the area being tested.
     289 * @param count Number of pages in the area being tested.
     290 * @param avoid Do not touch this area.
    293291 *
    294292 * @return True if there is no conflict, false otherwise.
     
    296294 */
    297295NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr,
    298     size_t count, bool guarded, as_area_t *avoid)
     296    size_t count, as_area_t *avoid)
    299297{
    300298        ASSERT((addr % PAGE_SIZE) == 0);
    301299        ASSERT(mutex_locked(&as->lock));
    302 
    303         /*
    304          * If the addition of the supposed area address and size overflows,
    305          * report conflict.
    306          */
    307         if (overflows_into_positive(addr, P2SZ(count)))
    308                 return false;
    309300       
    310301        /*
     
    313304        if (overlaps(addr, P2SZ(count), (uintptr_t) NULL, PAGE_SIZE))
    314305                return false;
    315 
     306       
    316307        /*
    317308         * The leaf node is found in O(log n), where n is proportional to
     
    337328                if (area != avoid) {
    338329                        mutex_lock(&area->lock);
    339 
    340                         /*
    341                          * If at least one of the two areas are protected
    342                          * by the AS_AREA_GUARD flag then we must be sure
    343                          * that they are separated by at least one unmapped
    344                          * page.
    345                          */
    346                         int const gp = (guarded ||
    347                             (area->flags & AS_AREA_GUARD)) ? 1 : 0;
    348                        
    349                         /*
    350                          * The area comes from the left neighbour node, which
    351                          * means that there already are some areas in the leaf
    352                          * node, which in turn means that adding gp is safe and
    353                          * will not cause an integer overflow.
    354                          */
     330                       
    355331                        if (overlaps(addr, P2SZ(count), area->base,
    356                             P2SZ(area->pages + gp))) {
    357                                 mutex_unlock(&area->lock);
    358                                 return false;
    359                         }
    360                        
    361                         mutex_unlock(&area->lock);
    362                 }
    363         }
    364        
    365         node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);
    366         if (node) {
    367                 area = (as_area_t *) node->value[0];
    368                
    369                 if (area != avoid) {
    370                         int gp;
    371 
    372                         mutex_lock(&area->lock);
    373 
    374                         gp = (guarded || (area->flags & AS_AREA_GUARD)) ? 1 : 0;
    375                         if (gp && overflows(addr, P2SZ(count))) {
    376                                 /*
    377                                  * Guard page not needed if the supposed area
    378                                  * is adjacent to the end of the address space.
    379                                  * We already know that the following test is
    380                                  * going to fail...
    381                                  */
    382                                 gp--;
    383                         }
    384                        
    385                         if (overlaps(addr, P2SZ(count + gp), area->base,
    386332                            P2SZ(area->pages))) {
    387333                                mutex_unlock(&area->lock);
     
    393339        }
    394340       
     341        node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);
     342        if (node) {
     343                area = (as_area_t *) node->value[0];
     344               
     345                if (area != avoid) {
     346                        mutex_lock(&area->lock);
     347                       
     348                        if (overlaps(addr, P2SZ(count), area->base,
     349                            P2SZ(area->pages))) {
     350                                mutex_unlock(&area->lock);
     351                                return false;
     352                        }
     353                       
     354                        mutex_unlock(&area->lock);
     355                }
     356        }
     357       
    395358        /* Second, check the leaf node. */
    396359        btree_key_t i;
    397360        for (i = 0; i < leaf->keys; i++) {
    398361                area = (as_area_t *) leaf->value[i];
    399                 int agp;
    400                 int gp;
    401362               
    402363                if (area == avoid)
     
    404365               
    405366                mutex_lock(&area->lock);
    406 
    407                 gp = (guarded || (area->flags & AS_AREA_GUARD)) ? 1 : 0;
    408                 agp = gp;
    409 
    410                 /*
    411                  * Sanitize the two possible unsigned integer overflows.
    412                  */
    413                 if (gp && overflows(addr, P2SZ(count)))
    414                         gp--;
    415                 if (agp && overflows(area->base, P2SZ(area->pages)))
    416                         agp--;
    417 
    418                 if (overlaps(addr, P2SZ(count + gp), area->base,
    419                     P2SZ(area->pages + agp))) {
     367               
     368                if (overlaps(addr, P2SZ(count), area->base,
     369                    P2SZ(area->pages))) {
    420370                        mutex_unlock(&area->lock);
    421371                        return false;
     
    427377        /*
    428378         * So far, the area does not conflict with other areas.
    429          * Check if it is contained in the user address space.
     379         * Check if it doesn't conflict with kernel address space.
    430380         */
    431381        if (!KERNEL_ADDRESS_SPACE_SHADOWED) {
    432                 return iswithin(USER_ADDRESS_SPACE_START,
    433                     (USER_ADDRESS_SPACE_END - USER_ADDRESS_SPACE_START) + 1,
    434                     addr, P2SZ(count));
     382                return !overlaps(addr, P2SZ(count), KERNEL_ADDRESS_SPACE_START,
     383                    KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START);
    435384        }
    436385       
     
    443392 * this function.
    444393 *
    445  * @param as      Address space.
    446  * @param bound   Lowest address bound.
    447  * @param size    Requested size of the allocation.
    448  * @param guarded True if the allocation must be protected by guard pages.
     394 * @param as    Address space.
     395 * @param bound Lowest address bound.
     396 * @param size  Requested size of the allocation.
    449397 *
    450398 * @return Address of the beginning of unmapped address space area.
     
    453401 */
    454402NO_TRACE static uintptr_t as_get_unmapped_area(as_t *as, uintptr_t bound,
    455     size_t size, bool guarded)
     403    size_t size)
    456404{
    457405        ASSERT(mutex_locked(&as->lock));
     
    475423        /* First check the bound address itself */
    476424        uintptr_t addr = ALIGN_UP(bound, PAGE_SIZE);
    477         if (addr >= bound) {
    478                 if (guarded) {
    479                         /* Leave an unmapped page between the lower
    480                          * bound and the area's start address.
    481                          */
    482                         addr += P2SZ(1);
    483                 }
    484 
    485                 if (check_area_conflicts(as, addr, pages, guarded, NULL))
    486                         return addr;
    487         }
     425        if ((addr >= bound) &&
     426            (check_area_conflicts(as, addr, pages, NULL)))
     427                return addr;
    488428       
    489429        /* Eventually check the addresses behind each area */
     
    499439                        addr =
    500440                            ALIGN_UP(area->base + P2SZ(area->pages), PAGE_SIZE);
    501 
    502                         if (guarded || area->flags & AS_AREA_GUARD) {
    503                                 /* We must leave an unmapped page
    504                                  * between the two areas.
    505                                  */
    506                                 addr += P2SZ(1);
    507                         }
    508 
    509441                        bool avail =
    510442                            ((addr >= bound) && (addr >= area->base) &&
    511                             (check_area_conflicts(as, addr, pages, guarded, area)));
     443                            (check_area_conflicts(as, addr, pages, area)));
    512444                       
    513445                        mutex_unlock(&area->lock);
     
    544476    mem_backend_data_t *backend_data, uintptr_t *base, uintptr_t bound)
    545477{
    546         if ((*base != (uintptr_t) -1) && !IS_ALIGNED(*base, PAGE_SIZE))
     478        if ((*base != (uintptr_t) -1) && ((*base % PAGE_SIZE) != 0))
    547479                return NULL;
    548480       
    549481        if (size == 0)
    550482                return NULL;
    551 
     483       
    552484        size_t pages = SIZE2FRAMES(size);
    553485       
     
    555487        if ((flags & AS_AREA_EXEC) && (flags & AS_AREA_WRITE))
    556488                return NULL;
    557 
    558         bool const guarded = flags & AS_AREA_GUARD;
    559489       
    560490        mutex_lock(&as->lock);
    561491       
    562492        if (*base == (uintptr_t) -1) {
    563                 *base = as_get_unmapped_area(as, bound, size, guarded);
     493                *base = as_get_unmapped_area(as, bound, size);
    564494                if (*base == (uintptr_t) -1) {
    565495                        mutex_unlock(&as->lock);
     
    567497                }
    568498        }
    569 
    570         if (overflows_into_positive(*base, size))
    571                 return NULL;
    572 
    573         if (!check_area_conflicts(as, *base, pages, guarded, NULL)) {
     499       
     500        if (!check_area_conflicts(as, *base, pages, NULL)) {
    574501                mutex_unlock(&as->lock);
    575502                return NULL;
     
    688615int as_area_resize(as_t *as, uintptr_t address, size_t size, unsigned int flags)
    689616{
    690         if (!IS_ALIGNED(address, PAGE_SIZE))
    691                 return EINVAL;
    692 
    693617        mutex_lock(&as->lock);
    694618       
     
    701625                return ENOENT;
    702626        }
    703 
    704         if (!area->backend->is_resizable(area)) {
    705                 /*
    706                  * The backend does not support resizing for this area.
     627       
     628        if (area->backend == &phys_backend) {
     629                /*
     630                 * Remapping of address space areas associated
     631                 * with memory mapped devices is not supported.
    707632                 */
    708633                mutex_unlock(&area->lock);
     
    740665               
    741666                page_table_lock(as, false);
     667               
     668                /*
     669                 * Start TLB shootdown sequence.
     670                 */
     671                ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid,
     672                    area->base + P2SZ(pages), area->pages - pages);
    742673               
    743674                /*
     
    795726                                }
    796727                               
    797                                 /*
    798                                  * Start TLB shootdown sequence.
    799                                  *
    800                                  * The sequence is rather short and can be
    801                                  * repeated multiple times. The reason is that
    802                                  * we don't want to have used_space_remove()
    803                                  * inside the sequence as it may use a blocking
    804                                  * memory allocation for its B+tree. Blocking
    805                                  * while holding the tlblock spinlock is
    806                                  * forbidden and would hit a kernel assertion.
    807                                  */
    808 
    809                                 ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES,
    810                                     as->asid, area->base + P2SZ(pages),
    811                                     area->pages - pages);
    812                
    813728                                for (; i < size; i++) {
    814729                                        pte_t *pte = page_mapping_find(as,
     
    828743                                        page_mapping_remove(as, ptr + P2SZ(i));
    829744                                }
    830                
    831                                 /*
    832                                  * Finish TLB shootdown sequence.
    833                                  */
    834                
    835                                 tlb_invalidate_pages(as->asid,
    836                                     area->base + P2SZ(pages),
    837                                     area->pages - pages);
    838                
    839                                 /*
    840                                  * Invalidate software translation caches
    841                                  * (e.g. TSB on sparc64, PHT on ppc32).
    842                                  */
    843                                 as_invalidate_translation_cache(as,
    844                                     area->base + P2SZ(pages),
    845                                     area->pages - pages);
    846                                 tlb_shootdown_finalize(ipl);
    847745                        }
    848746                }
     747               
     748                /*
     749                 * Finish TLB shootdown sequence.
     750                 */
     751               
     752                tlb_invalidate_pages(as->asid, area->base + P2SZ(pages),
     753                    area->pages - pages);
     754               
     755                /*
     756                 * Invalidate software translation caches
     757                 * (e.g. TSB on sparc64, PHT on ppc32).
     758                 */
     759                as_invalidate_translation_cache(as, area->base + P2SZ(pages),
     760                    area->pages - pages);
     761                tlb_shootdown_finalize(ipl);
     762               
    849763                page_table_unlock(as, false);
    850764        } else {
    851765                /*
    852766                 * Growing the area.
    853                  */
    854 
    855                 if (overflows_into_positive(address, P2SZ(pages)))
    856                         return EINVAL;
    857 
    858                 /*
    859767                 * Check for overlaps with other address space areas.
    860768                 */
    861                 bool const guarded = area->flags & AS_AREA_GUARD;
    862                 if (!check_area_conflicts(as, address, pages, guarded, area)) {
     769                if (!check_area_conflicts(as, address, pages, area)) {
    863770                        mutex_unlock(&area->lock);
    864771                        mutex_unlock(&as->lock);
     
    1061968        }
    1062969       
    1063         if (!src_area->backend->is_shareable(src_area)) {
    1064                 /*
    1065                  * The backend does not permit sharing of this area.
     970        if ((!src_area->backend) || (!src_area->backend->share)) {
     971                /*
     972                 * There is no backend or the backend does not
     973                 * know how to share the area.
    1066974                 */
    1067975                mutex_unlock(&src_area->lock);
     
    13531261 * Interrupts are assumed disabled.
    13541262 *
    1355  * @param address Faulting address.
    1356  * @param access  Access mode that caused the page fault (i.e.
    1357  *                read/write/exec).
    1358  * @param istate  Pointer to the interrupted state.
     1263 * @param page   Faulting page.
     1264 * @param access Access mode that caused the page fault (i.e.
     1265 *               read/write/exec).
     1266 * @param istate Pointer to the interrupted state.
    13591267 *
    13601268 * @return AS_PF_FAULT on page fault.
     
    13641272 *
    13651273 */
    1366 int as_page_fault(uintptr_t address, pf_access_t access, istate_t *istate)
    1367 {
    1368         uintptr_t page = ALIGN_DOWN(address, PAGE_SIZE);
    1369         int rc = AS_PF_FAULT;
    1370 
     1274int as_page_fault(uintptr_t page, pf_access_t access, istate_t *istate)
     1275{
    13711276        if (!THREAD)
    1372                 goto page_fault;
     1277                return AS_PF_FAULT;
    13731278       
    13741279        if (!AS)
    1375                 goto page_fault;
     1280                return AS_PF_FAULT;
    13761281       
    13771282        mutex_lock(&AS->lock);
     
    14291334         * Resort to the backend page fault handler.
    14301335         */
    1431         rc = area->backend->page_fault(area, page, access);
    1432         if (rc != AS_PF_OK) {
     1336        if (area->backend->page_fault(area, page, access) != AS_PF_OK) {
    14331337                page_table_unlock(AS, false);
    14341338                mutex_unlock(&area->lock);
     
    14511355                istate_set_retaddr(istate,
    14521356                    (uintptr_t) &memcpy_to_uspace_failover_address);
    1453         } else if (rc == AS_PF_SILENT) {
    1454                 printf("Killing task %" PRIu64 " due to a "
    1455                     "failed late reservation request.\n", TASK->taskid);
    1456                 task_kill_self(true);
    14571357        } else {
    1458                 fault_if_from_uspace(istate, "Page fault: %p.", (void *) address);
    1459                 panic_memtrap(istate, access, address, NULL);
     1358                return AS_PF_FAULT;
    14601359        }
    14611360       
     
    16831582{
    16841583        ASSERT(mutex_locked(&area->lock));
    1685         ASSERT(IS_ALIGNED(page, PAGE_SIZE));
     1584        ASSERT(page == ALIGN_DOWN(page, PAGE_SIZE));
    16861585        ASSERT(count);
    16871586       
     
    19671866{
    19681867        ASSERT(mutex_locked(&area->lock));
    1969         ASSERT(IS_ALIGNED(page, PAGE_SIZE));
     1868        ASSERT(page == ALIGN_DOWN(page, PAGE_SIZE));
    19701869        ASSERT(count);
    19711870       
     
    21442043{
    21452044        uintptr_t virt = base;
    2146         as_area_t *area = as_area_create(AS, flags, size,
     2045        as_area_t *area = as_area_create(AS, flags | AS_AREA_CACHEABLE, size,
    21472046            AS_AREA_ATTR_NONE, &anon_backend, NULL, &virt, bound);
    21482047        if (area == NULL)
Note: See TracChangeset for help on using the changeset viewer.