Ignore:
File:
1 edited

Legend:

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

    rf97f1e51 r908bb96  
    7979#include <syscall/copy.h>
    8080#include <arch/interrupt.h>
     81#include <interrupt.h>
    8182
    8283/**
     
    285286/** Check area conflicts with other areas.
    286287 *
    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.
     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.
    291293 *
    292294 * @return True if there is no conflict, false otherwise.
     
    294296 */
    295297NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr,
    296     size_t count, as_area_t *avoid)
     298    size_t count, bool guarded, as_area_t *avoid)
    297299{
    298300        ASSERT((addr % PAGE_SIZE) == 0);
    299301        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;
    300309       
    301310        /*
     
    304313        if (overlaps(addr, P2SZ(count), (uintptr_t) NULL, PAGE_SIZE))
    305314                return false;
    306        
     315
    307316        /*
    308317         * The leaf node is found in O(log n), where n is proportional to
     
    328337                if (area != avoid) {
    329338                        mutex_lock(&area->lock);
    330                        
     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                         */
    331355                        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,
    332386                            P2SZ(area->pages))) {
    333387                                mutex_unlock(&area->lock);
     
    339393        }
    340394       
    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        
    358395        /* Second, check the leaf node. */
    359396        btree_key_t i;
    360397        for (i = 0; i < leaf->keys; i++) {
    361398                area = (as_area_t *) leaf->value[i];
     399                int agp;
     400                int gp;
    362401               
    363402                if (area == avoid)
     
    365404               
    366405                mutex_lock(&area->lock);
    367                
    368                 if (overlaps(addr, P2SZ(count), area->base,
    369                     P2SZ(area->pages))) {
     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))) {
    370420                        mutex_unlock(&area->lock);
    371421                        return false;
     
    377427        /*
    378428         * So far, the area does not conflict with other areas.
    379          * Check if it doesn't conflict with kernel address space.
     429         * Check if it is contained in the user address space.
    380430         */
    381431        if (!KERNEL_ADDRESS_SPACE_SHADOWED) {
    382                 return !overlaps(addr, P2SZ(count), KERNEL_ADDRESS_SPACE_START,
    383                     KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START);
     432                return iswithin(USER_ADDRESS_SPACE_START,
     433                    (USER_ADDRESS_SPACE_END - USER_ADDRESS_SPACE_START) + 1,
     434                    addr, P2SZ(count));
    384435        }
    385436       
     
    392443 * this function.
    393444 *
    394  * @param as    Address space.
    395  * @param bound Lowest address bound.
    396  * @param size  Requested size of the allocation.
     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.
    397449 *
    398450 * @return Address of the beginning of unmapped address space area.
     
    401453 */
    402454NO_TRACE static uintptr_t as_get_unmapped_area(as_t *as, uintptr_t bound,
    403     size_t size)
     455    size_t size, bool guarded)
    404456{
    405457        ASSERT(mutex_locked(&as->lock));
     
    423475        /* First check the bound address itself */
    424476        uintptr_t addr = ALIGN_UP(bound, PAGE_SIZE);
    425         if ((addr >= bound) &&
    426             (check_area_conflicts(as, addr, pages, NULL)))
    427                 return addr;
     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        }
    428488       
    429489        /* Eventually check the addresses behind each area */
     
    439499                        addr =
    440500                            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
    441509                        bool avail =
    442510                            ((addr >= bound) && (addr >= area->base) &&
    443                             (check_area_conflicts(as, addr, pages, area)));
     511                            (check_area_conflicts(as, addr, pages, guarded, area)));
    444512                       
    445513                        mutex_unlock(&area->lock);
     
    481549        if (size == 0)
    482550                return NULL;
    483        
     551
    484552        size_t pages = SIZE2FRAMES(size);
    485553       
     
    487555        if ((flags & AS_AREA_EXEC) && (flags & AS_AREA_WRITE))
    488556                return NULL;
     557
     558        bool const guarded = flags & AS_AREA_GUARD;
    489559       
    490560        mutex_lock(&as->lock);
    491561       
    492562        if (*base == (uintptr_t) -1) {
    493                 *base = as_get_unmapped_area(as, bound, size);
     563                *base = as_get_unmapped_area(as, bound, size, guarded);
    494564                if (*base == (uintptr_t) -1) {
    495565                        mutex_unlock(&as->lock);
     
    497567                }
    498568        }
    499        
    500         if (!check_area_conflicts(as, *base, pages, NULL)) {
     569
     570        if (overflows_into_positive(*base, size))
     571                return NULL;
     572
     573        if (!check_area_conflicts(as, *base, pages, guarded, NULL)) {
    501574                mutex_unlock(&as->lock);
    502575                return NULL;
     
    625698                return ENOENT;
    626699        }
    627        
    628         if (area->backend == &phys_backend) {
    629                 /*
    630                  * Remapping of address space areas associated
    631                  * with memory mapped devices is not supported.
     700
     701        if (!area->backend->is_resizable(area)) {
     702                /*
     703                 * The backend does not support resizing for this area.
    632704                 */
    633705                mutex_unlock(&area->lock);
     
    665737               
    666738                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);
    673739               
    674740                /*
     
    726792                                }
    727793                               
     794                                /*
     795                                 * Start TLB shootdown sequence.
     796                                 *
     797                                 * The sequence is rather short and can be
     798                                 * repeated multiple times. The reason is that
     799                                 * we don't want to have used_space_remove()
     800                                 * inside the sequence as it may use a blocking
     801                                 * memory allocation for its B+tree. Blocking
     802                                 * while holding the tlblock spinlock is
     803                                 * forbidden and would hit a kernel assertion.
     804                                 */
     805
     806                                ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES,
     807                                    as->asid, area->base + P2SZ(pages),
     808                                    area->pages - pages);
     809               
    728810                                for (; i < size; i++) {
    729811                                        pte_t *pte = page_mapping_find(as,
     
    743825                                        page_mapping_remove(as, ptr + P2SZ(i));
    744826                                }
     827               
     828                                /*
     829                                 * Finish TLB shootdown sequence.
     830                                 */
     831               
     832                                tlb_invalidate_pages(as->asid,
     833                                    area->base + P2SZ(pages),
     834                                    area->pages - pages);
     835               
     836                                /*
     837                                 * Invalidate software translation caches
     838                                 * (e.g. TSB on sparc64, PHT on ppc32).
     839                                 */
     840                                as_invalidate_translation_cache(as,
     841                                    area->base + P2SZ(pages),
     842                                    area->pages - pages);
     843                                tlb_shootdown_finalize(ipl);
    745844                        }
    746845                }
    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                
    763846                page_table_unlock(as, false);
    764847        } else {
    765848                /*
    766849                 * Growing the area.
     850                 */
     851
     852                if (overflows_into_positive(address, P2SZ(pages)))
     853                        return EINVAL;
     854
     855                /*
    767856                 * Check for overlaps with other address space areas.
    768857                 */
    769                 if (!check_area_conflicts(as, address, pages, area)) {
     858                bool const guarded = area->flags & AS_AREA_GUARD;
     859                if (!check_area_conflicts(as, address, pages, guarded, area)) {
    770860                        mutex_unlock(&area->lock);
    771861                        mutex_unlock(&as->lock);
     
    9681058        }
    9691059       
    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.
     1060        if (!src_area->backend->is_shareable(src_area)) {
     1061                /*
     1062                 * The backend does not permit sharing of this area.
    9741063                 */
    9751064                mutex_unlock(&src_area->lock);
     
    12741363int as_page_fault(uintptr_t page, pf_access_t access, istate_t *istate)
    12751364{
     1365        int rc = AS_PF_FAULT;
     1366
    12761367        if (!THREAD)
    1277                 return AS_PF_FAULT;
     1368                goto page_fault;
    12781369       
    12791370        if (!AS)
    1280                 return AS_PF_FAULT;
     1371                goto page_fault;
    12811372       
    12821373        mutex_lock(&AS->lock);
     
    13341425         * Resort to the backend page fault handler.
    13351426         */
    1336         if (area->backend->page_fault(area, page, access) != AS_PF_OK) {
     1427        rc = area->backend->page_fault(area, page, access);
     1428        if (rc != AS_PF_OK) {
    13371429                page_table_unlock(AS, false);
    13381430                mutex_unlock(&area->lock);
     
    13551447                istate_set_retaddr(istate,
    13561448                    (uintptr_t) &memcpy_to_uspace_failover_address);
     1449        } else if (rc == AS_PF_SILENT) {
     1450                printf("Killing task %" PRIu64 " due to a "
     1451                    "failed late reservation request.\n", TASK->taskid);
     1452                task_kill_self(true);
    13571453        } else {
    1358                 return AS_PF_FAULT;
     1454                fault_if_from_uspace(istate, "Page fault: %p.", (void *) page);
     1455                panic_memtrap(istate, access, page, NULL);
    13591456        }
    13601457       
Note: See TracChangeset for help on using the changeset viewer.