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 | } |