Subversion Repositories HelenOS-historic

Rev

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

Rev 973 Rev 977
Line 67... Line 67...
67
 
67
 
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
 
73
 
73
/** Initialize address space subsystem. */
74
/** Initialize address space subsystem. */
74
void as_init(void)
75
void as_init(void)
75
{
76
{
76
    as_arch_init();
77
    as_arch_init();
Line 166... Line 167...
166
 * @param page Virtual page within the area.
167
 * @param page Virtual page within the area.
167
 * @param frame Physical frame to which page will be mapped.
168
 * @param frame Physical frame to which page will be mapped.
168
 */
169
 */
169
void as_set_mapping(as_t *as, __address page, __address frame)
170
void as_set_mapping(as_t *as, __address page, __address frame)
170
{
171
{
171
    as_area_t *a, *area = NULL;
172
    as_area_t *area;
172
    link_t *cur;
-
 
173
    ipl_t ipl;
173
    ipl_t ipl;
174
   
174
   
175
    ipl = interrupts_disable();
175
    ipl = interrupts_disable();
176
    spinlock_lock(&as->lock);
176
    spinlock_lock(&as->lock);
177
   
177
   
178
    /*
-
 
179
     * First, try locate an area.
-
 
180
     */
-
 
181
    for (cur = as->as_area_head.next; cur != &as->as_area_head; cur = cur->next) {
-
 
182
        a = list_get_instance(cur, as_area_t, link);
178
    area = find_area_and_lock(as, page);
183
        spinlock_lock(&a->lock);
-
 
184
 
-
 
185
        if ((page >= a->base) && (page < a->base + a->size * PAGE_SIZE)) {
-
 
186
            area = a;
-
 
187
            break;
-
 
188
        }
-
 
189
       
-
 
190
        spinlock_unlock(&a->lock);
-
 
191
    }
-
 
192
   
-
 
193
    if (!area) {
179
    if (!area) {
194
        panic("page not part of any as_area\n");
180
        panic("page not part of any as_area\n");
195
    }
181
    }
196
 
182
 
197
    /*
-
 
198
     * Note: area->lock is held.
-
 
199
     */
-
 
200
   
-
 
201
    page_mapping_insert(as, page, frame, get_area_flags(area));
183
    page_mapping_insert(as, page, frame, get_area_flags(area));
202
   
184
   
203
    spinlock_unlock(&area->lock);
185
    spinlock_unlock(&area->lock);
204
    spinlock_unlock(&as->lock);
186
    spinlock_unlock(&as->lock);
205
    interrupts_restore(ipl);
187
    interrupts_restore(ipl);
Line 214... Line 196...
214
 *
196
 *
215
 * @return 0 on page fault, 1 on success.
197
 * @return 0 on page fault, 1 on success.
216
 */
198
 */
217
int as_page_fault(__address page)
199
int as_page_fault(__address page)
218
{
200
{
219
    link_t *cur;
-
 
220
    as_area_t *a, *area = NULL;
201
    as_area_t *area;
221
    __address frame;
202
    __address frame;
222
   
203
   
223
    ASSERT(AS);
204
    ASSERT(AS);
224
    spinlock_lock(&AS->lock);
205
    spinlock_lock(&AS->lock);
225
   
206
   
226
    /*
-
 
227
     * Search this areas of this address space for presence of 'page'.
-
 
228
     */
-
 
229
    for (cur = AS->as_area_head.next; cur != &AS->as_area_head; cur = cur->next) {
-
 
230
        a = list_get_instance(cur, as_area_t, link);
-
 
231
        spinlock_lock(&a->lock);
-
 
232
 
-
 
233
        if ((page >= a->base) && (page < a->base + a->size * PAGE_SIZE)) {
-
 
234
 
-
 
235
            /*
-
 
236
             * We found the area containing 'page'.
207
    area = find_area_and_lock(AS, page);   
237
             * TODO: access checking
-
 
238
             */
-
 
239
            area = a;
-
 
240
            break;
-
 
241
        }
-
 
242
       
-
 
243
        spinlock_unlock(&a->lock);
-
 
244
    }
-
 
245
   
-
 
246
    if (!area) {
208
    if (!area) {
247
        /*
209
        /*
248
         * No area contained mapping for 'page'.
210
         * No area contained mapping for 'page'.
249
         * Signal page fault to low-level handler.
211
         * Signal page fault to low-level handler.
250
         */
212
         */
251
        spinlock_unlock(&AS->lock);
213
        spinlock_unlock(&AS->lock);
252
        return 0;
214
        return 0;
253
    }
215
    }
254
 
216
 
255
    /*
217
    /*
256
     * Note: area->lock is held.
-
 
257
     */
-
 
258
   
-
 
259
    /*
-
 
260
     * In general, there can be several reasons that
218
     * In general, there can be several reasons that
261
     * can have caused this fault.
219
     * can have caused this fault.
262
     *
220
     *
263
     * - non-existent mapping: the area is a scratch
221
     * - non-existent mapping: the area is a scratch
264
     *   area (e.g. stack) and so far has not been
222
     *   area (e.g. stack) and so far has not been
Line 397... Line 355...
397
        ASSERT(as_operations);
355
        ASSERT(as_operations);
398
        ASSERT(as_operations->page_table_create);
356
        ASSERT(as_operations->page_table_create);
399
 
357
 
400
        return as_operations->page_table_create(flags);
358
        return as_operations->page_table_create(flags);
401
}
359
}
-
 
360
 
-
 
361
/** Find address space area and change it.
-
 
362
 *
-
 
363
 * @param as Address space.
-
 
364
 * @param address Virtual address belonging to the area to be changed. Must be page-aligned.
-
 
365
 * @param size New size of the virtual memory block starting at address.
-
 
366
 * @param flags Flags influencing the remap operation. Currently unused.
-
 
367
 *
-
 
368
 * @return address on success, (__address) -1 otherwise.
-
 
369
 */
-
 
370
__address as_remap(as_t *as, __address address, size_t size, int flags)
-
 
371
{
-
 
372
    as_area_t *area = NULL;
-
 
373
    ipl_t ipl;
-
 
374
    size_t pages;
-
 
375
   
-
 
376
    ipl = interrupts_disable();
-
 
377
    spinlock_lock(&as->lock);
-
 
378
   
-
 
379
    /*
-
 
380
     * Locate the area.
-
 
381
     */
-
 
382
    area = find_area_and_lock(as, address);
-
 
383
    if (!area) {
-
 
384
        spinlock_unlock(&as->lock);
-
 
385
        return (__address) -1;
-
 
386
    }
-
 
387
 
-
 
388
    pages = SIZE2FRAMES((address - area->base) + size);
-
 
389
    if (pages < area->size) {
-
 
390
        int i;
-
 
391
 
-
 
392
        /*
-
 
393
         * Shrinking the area.
-
 
394
         */
-
 
395
        for (i = pages; i < area->size; i++) {
-
 
396
            pte_t *pte;
-
 
397
           
-
 
398
            /*
-
 
399
             * Releasing physical memory.
-
 
400
             * This depends on the fact that the memory was allocated using frame_alloc().
-
 
401
             */
-
 
402
            pte = page_mapping_find(as, area->base + i*PAGE_SIZE);
-
 
403
            if (pte) {
-
 
404
                ASSERT(PTE_PRESENT(pte));
-
 
405
                frame_free(ADDR2PFN(PTE_GET_FRAME(pte)));
-
 
406
            }
-
 
407
            page_mapping_remove(as, area->base + i*PAGE_SIZE);
-
 
408
        }
-
 
409
        /*
-
 
410
         * Invalidate TLB's.
-
 
411
         */
-
 
412
        tlb_shootdown_start(TLB_INVL_PAGES, AS->asid, area->base + pages*PAGE_SIZE, area->size - pages);
-
 
413
        tlb_invalidate_pages(AS->asid, area->base + pages*PAGE_SIZE, area->size - pages);
-
 
414
        tlb_shootdown_finalize();
-
 
415
    } else {
-
 
416
        /*
-
 
417
         * Growing the area.
-
 
418
         */
-
 
419
        area->size = size;
-
 
420
    }
-
 
421
   
-
 
422
    spinlock_unlock(&area->lock);
-
 
423
    spinlock_unlock(&as->lock);
-
 
424
    interrupts_restore(ipl);
-
 
425
 
-
 
426
    return address;
-
 
427
}
-
 
428
 
-
 
429
/** Find address space area and lock it.
-
 
430
 *
-
 
431
 * The address space must be locked and interrupts must be disabled.
-
 
432
 *
-
 
433
 * @param as Address space.
-
 
434
 * @param va Virtual address.
-
 
435
 *
-
 
436
 * @return Locked address space area containing va on success or NULL on failure.
-
 
437
 */
-
 
438
as_area_t *find_area_and_lock(as_t *as, __address va)
-
 
439
{
-
 
440
    link_t *cur;
-
 
441
    as_area_t *a;
-
 
442
   
-
 
443
    for (cur = as->as_area_head.next; cur != &as->as_area_head; cur = cur->next) {
-
 
444
        a = list_get_instance(cur, as_area_t, link);
-
 
445
        spinlock_lock(&a->lock);
-
 
446
 
-
 
447
        if ((va >= a->base) && (va < a->base + a->size * PAGE_SIZE))
-
 
448
             return a;
-
 
449
       
-
 
450
        spinlock_unlock(&a->lock);
-
 
451
    }
-
 
452
 
-
 
453
    return NULL;
-
 
454
}