Rev 973 | Rev 983 | 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 | } |