Subversion Repositories HelenOS-historic

Rev

Rev 1044 | Rev 1070 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1044 Rev 1048
Line 68... Line 68...
68
/** Kernel address space. */
68
/** Kernel address space. */
69
as_t *AS_KERNEL = NULL;
69
as_t *AS_KERNEL = NULL;
70
 
70
 
71
static int get_area_flags(as_area_t *a);
71
static int get_area_flags(as_area_t *a);
72
static as_area_t *find_area_and_lock(as_t *as, __address va);
72
static as_area_t *find_area_and_lock(as_t *as, __address va);
-
 
73
static bool check_area_conflicts(as_t *as, __address va, size_t size, as_area_t *avoid_area);
73
 
74
 
74
/** Initialize address space subsystem. */
75
/** Initialize address space subsystem. */
75
void as_init(void)
76
void as_init(void)
76
{
77
{
77
    as_arch_init();
78
    as_arch_init();
Line 118... Line 119...
118
 *
119
 *
119
 * The created address space area is added to the target address space.
120
 * The created address space area is added to the target address space.
120
 *
121
 *
121
 * @param as Target address space.
122
 * @param as Target address space.
122
 * @param flags Flags of the area.
123
 * @param flags Flags of the area.
123
 * @param size Size of area in multiples of PAGE_SIZE.
124
 * @param size Size of area.
124
 * @param base Base address of area.
125
 * @param base Base address of area.
125
 *
126
 *
126
 * @return Address space area on success or NULL on failure.
127
 * @return Address space area on success or NULL on failure.
127
 */
128
 */
128
as_area_t *as_area_create(as_t *as, int flags, size_t size, __address base)
129
as_area_t *as_area_create(as_t *as, int flags, size_t size, __address base)
129
{
130
{
130
    ipl_t ipl;
131
    ipl_t ipl;
131
    as_area_t *a;
132
    as_area_t *a;
132
   
133
   
133
    if (base % PAGE_SIZE)
134
    if (base % PAGE_SIZE)
-
 
135
        return NULL;
-
 
136
 
134
        panic("addr not aligned to a page boundary");
137
    /* Writeable executable areas are not supported. */
-
 
138
    if ((flags & AS_AREA_EXEC) && (flags & AS_AREA_WRITE))
-
 
139
        return NULL;
135
   
140
   
136
    ipl = interrupts_disable();
141
    ipl = interrupts_disable();
137
    spinlock_lock(&as->lock);
142
    spinlock_lock(&as->lock);
138
   
143
   
139
    /*
-
 
140
     * TODO: test as_area which is to be created doesn't overlap with an existing one.
144
    if (!check_area_conflicts(as, base, size, NULL)) {
-
 
145
        spinlock_unlock(&as->lock);
-
 
146
        interrupts_restore(ipl);
-
 
147
        return NULL;
141
     */
148
    }
142
   
149
   
143
    a = (as_area_t *) malloc(sizeof(as_area_t), 0);
150
    a = (as_area_t *) malloc(sizeof(as_area_t), 0);
144
 
151
 
145
    spinlock_initialize(&a->lock, "as_area_lock");
152
    spinlock_initialize(&a->lock, "as_area_lock");
146
   
153
   
147
    link_initialize(&a->link);         
154
    link_initialize(&a->link);         
148
    a->flags = flags;
155
    a->flags = flags;
149
    a->size = size;
156
    a->pages = SIZE2FRAMES(size);
150
    a->base = base;
157
    a->base = base;
151
   
158
   
152
    list_append(&a->link, &as->as_area_head);
159
    list_append(&a->link, &as->as_area_head);
153
 
160
 
154
    spinlock_unlock(&as->lock);
161
    spinlock_unlock(&as->lock);
Line 429... Line 436...
429
     * Locate the area.
436
     * Locate the area.
430
     */
437
     */
431
    area = find_area_and_lock(as, address);
438
    area = find_area_and_lock(as, address);
432
    if (!area) {
439
    if (!area) {
433
        spinlock_unlock(&as->lock);
440
        spinlock_unlock(&as->lock);
-
 
441
        interrupts_restore(ipl);
434
        return (__address) -1;
442
        return (__address) -1;
435
    }
443
    }
436
 
444
 
437
    pages = SIZE2FRAMES((address - area->base) + size);
445
    pages = SIZE2FRAMES((address - area->base) + size);
-
 
446
    if (!check_area_conflicts(as, address, pages * PAGE_SIZE, area)) {
-
 
447
        spinlock_unlock(&as->lock);
-
 
448
        interrupts_restore(ipl);
-
 
449
        return (__address) -1;
-
 
450
    }
-
 
451
 
438
    if (pages < area->size) {
452
    if (pages < area->pages) {
439
        int i;
453
        int i;
440
 
454
 
441
        /*
455
        /*
442
         * Shrinking the area.
456
         * Shrinking the area.
443
         */
457
         */
444
        for (i = pages; i < area->size; i++) {
458
        for (i = pages; i < area->pages; i++) {
445
            pte_t *pte;
459
            pte_t *pte;
446
           
460
           
447
            /*
461
            /*
448
             * Releasing physical memory.
462
             * Releasing physical memory.
449
             * This depends on the fact that the memory was allocated using frame_alloc().
463
             * This depends on the fact that the memory was allocated using frame_alloc().
Line 464... Line 478...
464
            }
478
            }
465
        }
479
        }
466
        /*
480
        /*
467
         * Invalidate TLB's.
481
         * Invalidate TLB's.
468
         */
482
         */
469
        tlb_shootdown_start(TLB_INVL_PAGES, AS->asid, area->base + pages*PAGE_SIZE, area->size - pages);
483
        tlb_shootdown_start(TLB_INVL_PAGES, AS->asid, area->base + pages*PAGE_SIZE, area->pages - pages);
470
        tlb_invalidate_pages(AS->asid, area->base + pages*PAGE_SIZE, area->size - pages);
484
        tlb_invalidate_pages(AS->asid, area->base + pages*PAGE_SIZE, area->pages - pages);
471
        tlb_shootdown_finalize();
485
        tlb_shootdown_finalize();
472
    }
486
    }
473
 
487
 
474
    area->size = pages;
488
    area->pages = pages;
475
   
489
   
476
    spinlock_unlock(&area->lock);
490
    spinlock_unlock(&area->lock);
477
    spinlock_unlock(&as->lock);
491
    spinlock_unlock(&as->lock);
478
    interrupts_restore(ipl);
492
    interrupts_restore(ipl);
479
 
493
 
Line 496... Line 510...
496
   
510
   
497
    for (cur = as->as_area_head.next; cur != &as->as_area_head; cur = cur->next) {
511
    for (cur = as->as_area_head.next; cur != &as->as_area_head; cur = cur->next) {
498
        a = list_get_instance(cur, as_area_t, link);
512
        a = list_get_instance(cur, as_area_t, link);
499
        spinlock_lock(&a->lock);
513
        spinlock_lock(&a->lock);
500
 
514
 
501
        if ((va >= a->base) && (va < a->base + a->size * PAGE_SIZE))
515
        if ((va >= a->base) && (va < a->base + a->pages * PAGE_SIZE))
502
             return a;
516
            return a;
503
       
517
       
504
        spinlock_unlock(&a->lock);
518
        spinlock_unlock(&a->lock);
505
    }
519
    }
506
 
520
 
507
    return NULL;
521
    return NULL;
508
}
522
}
-
 
523
 
-
 
524
/** Check area conflicts with other areas.
-
 
525
 *
-
 
526
 * The address space must be locked and interrupts must be disabled.
-
 
527
 *
-
 
528
 * @param as Address space.
-
 
529
 * @param va Starting virtual address of the area being tested.
-
 
530
 * @param size Size of the area being tested.
-
 
531
 * @param avoid_area Do not touch this area.
-
 
532
 *
-
 
533
 * @return True if there is no conflict, false otherwise.
-
 
534
 */
-
 
535
bool check_area_conflicts(as_t *as, __address va, size_t size, as_area_t *avoid_area)
-
 
536
{
-
 
537
    link_t *cur;
-
 
538
    as_area_t *a;
-
 
539
   
-
 
540
    for (cur = as->as_area_head.next; cur != &as->as_area_head; cur = cur->next) {
-
 
541
        __address start;
-
 
542
        __address end;
-
 
543
   
-
 
544
        a = list_get_instance(cur, as_area_t, link);
-
 
545
        if (a == avoid_area)
-
 
546
            continue;
-
 
547
           
-
 
548
        spinlock_lock(&a->lock);
-
 
549
 
-
 
550
        start = a->base;
-
 
551
        end = a->base + a->pages * PAGE_SIZE - 1;
-
 
552
 
-
 
553
        spinlock_unlock(&a->lock);
-
 
554
 
-
 
555
        if ((va >= start) && (va <= end)) {
-
 
556
            /*
-
 
557
             * Tested area is inside another area.
-
 
558
             */
-
 
559
            return false;
-
 
560
        }
-
 
561
       
-
 
562
        if ((start >= va) && (start < va + size)) {
-
 
563
            /*
-
 
564
             * Another area starts in tested area.
-
 
565
             */
-
 
566
            return false;
-
 
567
        }
-
 
568
       
-
 
569
        if ((end >= va) && (end < va + size)) {
-
 
570
            /*
-
 
571
             * Another area ends in tested area.
-
 
572
             */
-
 
573
            return false;
-
 
574
        }
-
 
575
 
-
 
576
    }
-
 
577
 
-
 
578
    return true;
-
 
579
}