source: mainline/kernel/generic/src/mm/as.c@ b910455

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b910455 was 0b37882, checked in by Martin Decky <martin@…>, 15 years ago

memory management work

  • implement as_get_mappable_page() as a new syscall (SYS_AS_GET_UNMAPPED_AREA), the kernel has a full knowledge of the address space areas, there is no need to duplicate this management in uspace)
  • make sure all address space/address space area manipulating functions use proper page alignment on base addresses and sizes (discrepancy with respect to this caused inconsistent behaviour, although no fatal bugs were probably present)
  • add forgotten tests (area != avoid) to check_area_conflicts()
  • unify size/page conversions (use always use bitwise shifts by PAGE_WIDTH)
  • new uspace heap allocator
    • basic next fit algorithm for better scalability (there is still space for optimizations)
    • support for multiple discontinuous heap areas (inspired by Jiri Tlach's implementation in lp:~jiri-tlach/helenos/nommu, but independent)
    • the "_heap" linker script symbol has been removed, the initial heap area is allocated according to as_get_mappable_page() (which uses the address of entry as the lower bound of the address space area base)
    • the hardwired 1 GB (4 GB respectivelly) heap size limit has been removed
    • the heap areas can be freely intermixed with other address space areas (e.g. mapped physical memory of devices, shared memory, etc.), the address space holes can be reused later (but still merging of adjunct address space areas is missing)
  • minor cstyle changes
  • Property mode set to 100644
File size: 53.5 KB
RevLine 
[20d50a1]1/*
[0321109]2 * Copyright (c) 2010 Jakub Jermar
[20d50a1]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[cc73a8a1]29/** @addtogroup genericmm
[b45c443]30 * @{
31 */
32
[9179d0a]33/**
[b45c443]34 * @file
[da1bafb]35 * @brief Address space related functions.
[9179d0a]36 *
[20d50a1]37 * This file contains address space manipulation functions.
38 * Roughly speaking, this is a higher-level client of
39 * Virtual Address Translation (VAT) subsystem.
[9179d0a]40 *
41 * Functionality provided by this file allows one to
[cc73a8a1]42 * create address spaces and create, resize and share
[9179d0a]43 * address space areas.
44 *
45 * @see page.c
46 *
[20d50a1]47 */
48
49#include <mm/as.h>
[ef67bab]50#include <arch/mm/as.h>
[20d50a1]51#include <mm/page.h>
52#include <mm/frame.h>
[085d973]53#include <mm/slab.h>
[20d50a1]54#include <mm/tlb.h>
55#include <arch/mm/page.h>
56#include <genarch/mm/page_pt.h>
[2802767]57#include <genarch/mm/page_ht.h>
[4512d7e]58#include <mm/asid.h>
[20d50a1]59#include <arch/mm/asid.h>
[31d8e10]60#include <preemption.h>
[20d50a1]61#include <synch/spinlock.h>
[1068f6a]62#include <synch/mutex.h>
[5c9a08b]63#include <adt/list.h>
[252127e]64#include <adt/btree.h>
[df0103f7]65#include <proc/task.h>
[e3c762cd]66#include <proc/thread.h>
[20d50a1]67#include <arch/asm.h>
[df0103f7]68#include <panic.h>
[20d50a1]69#include <debug.h>
[df0103f7]70#include <print.h>
[20d50a1]71#include <memstr.h>
[5a7d9d1]72#include <macros.h>
[0b37882]73#include <bitops.h>
[20d50a1]74#include <arch.h>
[df0103f7]75#include <errno.h>
76#include <config.h>
[25bf215]77#include <align.h>
[d99c1d2]78#include <typedefs.h>
[e3c762cd]79#include <syscall/copy.h>
80#include <arch/interrupt.h>
[20d50a1]81
[92778f2]82#ifdef CONFIG_VIRT_IDX_DCACHE
83#include <arch/mm/cache.h>
84#endif /* CONFIG_VIRT_IDX_DCACHE */
85
[cc73a8a1]86/**
87 * Each architecture decides what functions will be used to carry out
88 * address space operations such as creating or locking page tables.
89 */
[ef67bab]90as_operations_t *as_operations = NULL;
[20d50a1]91
[fc47885]92/** Slab for as_t objects.
[da1bafb]93 *
[57da95c]94 */
95static slab_cache_t *as_slab;
96
[fc47885]97/** ASID subsystem lock.
98 *
99 * This lock protects:
[879585a3]100 * - inactive_as_with_asid_head list
101 * - as->asid for each as of the as_t type
102 * - asids_allocated counter
[da1bafb]103 *
[6f4495f5]104 */
[879585a3]105SPINLOCK_INITIALIZE(asidlock);
[7e4e532]106
107/**
[fc47885]108 * Inactive address spaces (on all processors)
109 * that have valid ASID.
[7e4e532]110 */
111LIST_INITIALIZE(inactive_as_with_asid_head);
112
[071a8ae6]113/** Kernel address space. */
114as_t *AS_KERNEL = NULL;
115
[7a0359b]116NO_TRACE static int as_constructor(void *obj, unsigned int flags)
[29b2bbf]117{
118 as_t *as = (as_t *) obj;
[da1bafb]119
[29b2bbf]120 link_initialize(&as->inactive_as_with_asid_link);
[7f341820]121 mutex_initialize(&as->lock, MUTEX_PASSIVE);
[29b2bbf]122
[fc47885]123 return as_constructor_arch(as, flags);
[29b2bbf]124}
125
[7a0359b]126NO_TRACE static size_t as_destructor(void *obj)
[29b2bbf]127{
[fc47885]128 return as_destructor_arch((as_t *) obj);
[29b2bbf]129}
130
[ef67bab]131/** Initialize address space subsystem. */
132void as_init(void)
133{
134 as_arch_init();
[da1bafb]135
[29b2bbf]136 as_slab = slab_cache_create("as_slab", sizeof(as_t), 0,
[6f4495f5]137 as_constructor, as_destructor, SLAB_CACHE_MAGDEFERRED);
[57da95c]138
[8e1ea655]139 AS_KERNEL = as_create(FLAG_AS_KERNEL);
[125e944]140 if (!AS_KERNEL)
[f651e80]141 panic("Cannot create kernel address space.");
[125e944]142
[fc47885]143 /*
144 * Make sure the kernel address space
[76fca31]145 * reference count never drops to zero.
146 */
[6193351]147 as_hold(AS_KERNEL);
[ef67bab]148}
149
[071a8ae6]150/** Create address space.
151 *
[da1bafb]152 * @param flags Flags that influence the way in wich the address
153 * space is created.
154 *
[071a8ae6]155 */
[da1bafb]156as_t *as_create(unsigned int flags)
[20d50a1]157{
[da1bafb]158 as_t *as = (as_t *) slab_alloc(as_slab, 0);
[29b2bbf]159 (void) as_create_arch(as, 0);
160
[252127e]161 btree_create(&as->as_area_btree);
[bb68433]162
163 if (flags & FLAG_AS_KERNEL)
164 as->asid = ASID_KERNEL;
165 else
166 as->asid = ASID_INVALID;
167
[31d8e10]168 atomic_set(&as->refcount, 0);
[47800e0]169 as->cpu_refcount = 0;
[da1bafb]170
[b3f8fb7]171#ifdef AS_PAGE_TABLE
[80bcaed]172 as->genarch.page_table = page_table_create(flags);
[b3f8fb7]173#else
174 page_table_create(flags);
175#endif
[76fca31]176
[20d50a1]177 return as;
178}
179
[482826d]180/** Destroy adress space.
181 *
[6f4495f5]182 * When there are no tasks referencing this address space (i.e. its refcount is
183 * zero), the address space can be destroyed.
[31d8e10]184 *
185 * We know that we don't hold any spinlock.
[6745592]186 *
[da1bafb]187 * @param as Address space to be destroyed.
188 *
[482826d]189 */
190void as_destroy(as_t *as)
[5be1923]191{
[31d8e10]192 DEADLOCK_PROBE_INIT(p_asidlock);
[fc47885]193
[1624aae]194 ASSERT(as != AS);
[31d8e10]195 ASSERT(atomic_get(&as->refcount) == 0);
[482826d]196
197 /*
[663bb537]198 * Since there is no reference to this address space, it is safe not to
199 * lock its mutex.
[482826d]200 */
[fc47885]201
[31d8e10]202 /*
203 * We need to avoid deadlock between TLB shootdown and asidlock.
204 * We therefore try to take asid conditionally and if we don't succeed,
205 * we enable interrupts and try again. This is done while preemption is
206 * disabled to prevent nested context switches. We also depend on the
207 * fact that so far no spinlocks are held.
208 */
209 preemption_disable();
[da1bafb]210 ipl_t ipl = interrupts_read();
211
[31d8e10]212retry:
213 interrupts_disable();
214 if (!spinlock_trylock(&asidlock)) {
215 interrupts_enable();
216 DEADLOCK_PROBE(p_asidlock, DEADLOCK_THRESHOLD);
217 goto retry;
218 }
[da1bafb]219
220 /* Interrupts disabled, enable preemption */
221 preemption_enable();
222
223 if ((as->asid != ASID_INVALID) && (as != AS_KERNEL)) {
[1624aae]224 if (as->cpu_refcount == 0)
[31e8ddd]225 list_remove(&as->inactive_as_with_asid_link);
[da1bafb]226
[482826d]227 asid_put(as->asid);
228 }
[da1bafb]229
[879585a3]230 spinlock_unlock(&asidlock);
[fdaad75d]231 interrupts_restore(ipl);
[fc47885]232
[da1bafb]233
[482826d]234 /*
235 * Destroy address space areas of the address space.
[8440473]236 * The B+tree must be walked carefully because it is
[6f9a9bc]237 * also being destroyed.
[da1bafb]238 */
239 bool cond = true;
240 while (cond) {
[6f9a9bc]241 ASSERT(!list_empty(&as->as_area_btree.leaf_head));
[da1bafb]242
243 btree_node_t *node =
244 list_get_instance(as->as_area_btree.leaf_head.next,
[6f4495f5]245 btree_node_t, leaf_link);
[da1bafb]246
247 if ((cond = node->keys))
[6f9a9bc]248 as_area_destroy(as, node->key[0]);
[482826d]249 }
[da1bafb]250
[152b2b0]251 btree_destroy(&as->as_area_btree);
[da1bafb]252
[b3f8fb7]253#ifdef AS_PAGE_TABLE
[80bcaed]254 page_table_destroy(as->genarch.page_table);
[b3f8fb7]255#else
256 page_table_destroy(NULL);
257#endif
[da1bafb]258
[57da95c]259 slab_free(as_slab, as);
[5be1923]260}
261
[0321109]262/** Hold a reference to an address space.
263 *
[fc47885]264 * Holding a reference to an address space prevents destruction
265 * of that address space.
[0321109]266 *
[da1bafb]267 * @param as Address space to be held.
268 *
[0321109]269 */
[7a0359b]270NO_TRACE void as_hold(as_t *as)
[0321109]271{
272 atomic_inc(&as->refcount);
273}
274
275/** Release a reference to an address space.
276 *
[fc47885]277 * The last one to release a reference to an address space
278 * destroys the address space.
[0321109]279 *
[da1bafb]280 * @param asAddress space to be released.
281 *
[0321109]282 */
[7a0359b]283NO_TRACE void as_release(as_t *as)
[0321109]284{
285 if (atomic_predec(&as->refcount) == 0)
286 as_destroy(as);
287}
288
[e3ee9b9]289/** Check area conflicts with other areas.
290 *
[0b37882]291 * @param as Address space.
292 * @param addr Starting virtual address of the area being tested.
293 * @param count Number of pages in the area being tested.
294 * @param avoid Do not touch this area.
[e3ee9b9]295 *
296 * @return True if there is no conflict, false otherwise.
297 *
298 */
[0b37882]299NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr,
300 size_t count, as_area_t *avoid)
[e3ee9b9]301{
[0b37882]302 ASSERT((addr % PAGE_SIZE) == 0);
[e3ee9b9]303 ASSERT(mutex_locked(&as->lock));
304
305 /*
306 * We don't want any area to have conflicts with NULL page.
307 */
[0b37882]308 if (overlaps(addr, count << PAGE_WIDTH, (uintptr_t) NULL, PAGE_SIZE))
[e3ee9b9]309 return false;
310
311 /*
312 * The leaf node is found in O(log n), where n is proportional to
313 * the number of address space areas belonging to as.
314 * The check for conflicts is then attempted on the rightmost
315 * record in the left neighbour, the leftmost record in the right
316 * neighbour and all records in the leaf node itself.
317 */
318 btree_node_t *leaf;
319 as_area_t *area =
[0b37882]320 (as_area_t *) btree_search(&as->as_area_btree, addr, &leaf);
[e3ee9b9]321 if (area) {
[0b37882]322 if (area != avoid)
[e3ee9b9]323 return false;
324 }
325
326 /* First, check the two border cases. */
327 btree_node_t *node =
328 btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);
329 if (node) {
330 area = (as_area_t *) node->value[node->keys - 1];
331
[0b37882]332 if (area != avoid) {
333 mutex_lock(&area->lock);
334
335 if (overlaps(addr, count << PAGE_WIDTH,
336 area->base, area->pages << PAGE_WIDTH)) {
337 mutex_unlock(&area->lock);
338 return false;
339 }
340
[e3ee9b9]341 mutex_unlock(&area->lock);
342 }
343 }
344
345 node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);
346 if (node) {
347 area = (as_area_t *) node->value[0];
348
[0b37882]349 if (area != avoid) {
350 mutex_lock(&area->lock);
351
352 if (overlaps(addr, count << PAGE_WIDTH,
353 area->base, area->pages << PAGE_WIDTH)) {
354 mutex_unlock(&area->lock);
355 return false;
356 }
357
[e3ee9b9]358 mutex_unlock(&area->lock);
359 }
360 }
361
362 /* Second, check the leaf node. */
363 btree_key_t i;
364 for (i = 0; i < leaf->keys; i++) {
365 area = (as_area_t *) leaf->value[i];
366
[0b37882]367 if (area == avoid)
[e3ee9b9]368 continue;
369
370 mutex_lock(&area->lock);
371
[0b37882]372 if (overlaps(addr, count << PAGE_WIDTH,
373 area->base, area->pages << PAGE_WIDTH)) {
[e3ee9b9]374 mutex_unlock(&area->lock);
375 return false;
376 }
377
378 mutex_unlock(&area->lock);
379 }
380
381 /*
382 * So far, the area does not conflict with other areas.
383 * Check if it doesn't conflict with kernel address space.
384 */
385 if (!KERNEL_ADDRESS_SPACE_SHADOWED) {
[0b37882]386 return !overlaps(addr, count << PAGE_WIDTH,
[e3ee9b9]387 KERNEL_ADDRESS_SPACE_START,
388 KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START);
389 }
390
391 return true;
392}
393
[20d50a1]394/** Create address space area of common attributes.
395 *
396 * The created address space area is added to the target address space.
397 *
[da1bafb]398 * @param as Target address space.
399 * @param flags Flags of the area memory.
400 * @param size Size of area.
401 * @param base Base address of area.
402 * @param attrs Attributes of the area.
403 * @param backend Address space area backend. NULL if no backend is used.
404 * @param backend_data NULL or a pointer to an array holding two void *.
405 *
406 * @return Address space area on success or NULL on failure.
[20d50a1]407 *
408 */
[da1bafb]409as_area_t *as_area_create(as_t *as, unsigned int flags, size_t size,
410 uintptr_t base, unsigned int attrs, mem_backend_t *backend,
411 mem_backend_data_t *backend_data)
[20d50a1]412{
[0b37882]413 if ((base % PAGE_SIZE) != 0)
[37e7d2b9]414 return NULL;
[da1bafb]415
[0b37882]416 if (size == 0)
[dbbeb26]417 return NULL;
[da1bafb]418
[0b37882]419 size_t pages = SIZE2FRAMES(size);
420
[37e7d2b9]421 /* Writeable executable areas are not supported. */
422 if ((flags & AS_AREA_EXEC) && (flags & AS_AREA_WRITE))
423 return NULL;
[20d50a1]424
[1068f6a]425 mutex_lock(&as->lock);
[20d50a1]426
[0b37882]427 if (!check_area_conflicts(as, base, pages, NULL)) {
[1068f6a]428 mutex_unlock(&as->lock);
[37e7d2b9]429 return NULL;
430 }
[20d50a1]431
[da1bafb]432 as_area_t *area = (as_area_t *) malloc(sizeof(as_area_t), 0);
433
434 mutex_initialize(&area->lock, MUTEX_PASSIVE);
435
436 area->as = as;
437 area->flags = flags;
438 area->attributes = attrs;
[0b37882]439 area->pages = pages;
[fc47885]440 area->resident = 0;
[da1bafb]441 area->base = base;
442 area->sh_info = NULL;
443 area->backend = backend;
444
[0ee077ee]445 if (backend_data)
[da1bafb]446 area->backend_data = *backend_data;
[0ee077ee]447 else
[da1bafb]448 memsetb(&area->backend_data, sizeof(area->backend_data), 0);
449
450 btree_create(&area->used_space);
451 btree_insert(&as->as_area_btree, base, (void *) area, NULL);
[bb68433]452
[1068f6a]453 mutex_unlock(&as->lock);
[da1bafb]454
455 return area;
[20d50a1]456}
457
[e3ee9b9]458/** Find address space area and lock it.
459 *
460 * @param as Address space.
461 * @param va Virtual address.
462 *
463 * @return Locked address space area containing va on success or
464 * NULL on failure.
465 *
466 */
[7a0359b]467NO_TRACE static as_area_t *find_area_and_lock(as_t *as, uintptr_t va)
[e3ee9b9]468{
469 ASSERT(mutex_locked(&as->lock));
470
471 btree_node_t *leaf;
472 as_area_t *area = (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);
473 if (area) {
474 /* va is the base address of an address space area */
475 mutex_lock(&area->lock);
476 return area;
477 }
478
479 /*
480 * Search the leaf node and the righmost record of its left neighbour
481 * to find out whether this is a miss or va belongs to an address
482 * space area found there.
483 */
484
485 /* First, search the leaf node itself. */
486 btree_key_t i;
487
488 for (i = 0; i < leaf->keys; i++) {
489 area = (as_area_t *) leaf->value[i];
490
491 mutex_lock(&area->lock);
492
[0b37882]493 if ((area->base <= va) &&
494 (va < area->base + (area->pages << PAGE_WIDTH)))
[e3ee9b9]495 return area;
496
497 mutex_unlock(&area->lock);
498 }
499
500 /*
501 * Second, locate the left neighbour and test its last record.
502 * Because of its position in the B+tree, it must have base < va.
503 */
504 btree_node_t *lnode = btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);
505 if (lnode) {
506 area = (as_area_t *) lnode->value[lnode->keys - 1];
507
508 mutex_lock(&area->lock);
509
[0b37882]510 if (va < area->base + (area->pages << PAGE_WIDTH))
[e3ee9b9]511 return area;
512
513 mutex_unlock(&area->lock);
514 }
515
516 return NULL;
517}
518
[df0103f7]519/** Find address space area and change it.
520 *
[da1bafb]521 * @param as Address space.
522 * @param address Virtual address belonging to the area to be changed.
523 * Must be page-aligned.
524 * @param size New size of the virtual memory block starting at
525 * address.
526 * @param flags Flags influencing the remap operation. Currently unused.
527 *
528 * @return Zero on success or a value from @ref errno.h otherwise.
[df0103f7]529 *
[da1bafb]530 */
531int as_area_resize(as_t *as, uintptr_t address, size_t size, unsigned int flags)
[df0103f7]532{
[1068f6a]533 mutex_lock(&as->lock);
[df0103f7]534
535 /*
536 * Locate the area.
537 */
[da1bafb]538 as_area_t *area = find_area_and_lock(as, address);
[df0103f7]539 if (!area) {
[1068f6a]540 mutex_unlock(&as->lock);
[7242a78e]541 return ENOENT;
[df0103f7]542 }
[da1bafb]543
[0ee077ee]544 if (area->backend == &phys_backend) {
[df0103f7]545 /*
546 * Remapping of address space areas associated
547 * with memory mapped devices is not supported.
548 */
[1068f6a]549 mutex_unlock(&area->lock);
550 mutex_unlock(&as->lock);
[7242a78e]551 return ENOTSUP;
[df0103f7]552 }
[da1bafb]553
[8182031]554 if (area->sh_info) {
555 /*
[da1bafb]556 * Remapping of shared address space areas
[8182031]557 * is not supported.
558 */
559 mutex_unlock(&area->lock);
560 mutex_unlock(&as->lock);
561 return ENOTSUP;
562 }
[da1bafb]563
564 size_t pages = SIZE2FRAMES((address - area->base) + size);
[df0103f7]565 if (!pages) {
566 /*
567 * Zero size address space areas are not allowed.
568 */
[1068f6a]569 mutex_unlock(&area->lock);
570 mutex_unlock(&as->lock);
[7242a78e]571 return EPERM;
[df0103f7]572 }
573
574 if (pages < area->pages) {
[0b37882]575 uintptr_t start_free = area->base + (pages << PAGE_WIDTH);
[da1bafb]576
[df0103f7]577 /*
578 * Shrinking the area.
579 * No need to check for overlaps.
580 */
[da1bafb]581
[c964521]582 page_table_lock(as, false);
[da1bafb]583
[5552d60]584 /*
585 * Start TLB shootdown sequence.
586 */
[402eda5]587 ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid,
[0b37882]588 area->base + (pages << PAGE_WIDTH), area->pages - pages);
[da1bafb]589
[56789125]590 /*
591 * Remove frames belonging to used space starting from
592 * the highest addresses downwards until an overlap with
593 * the resized address space area is found. Note that this
594 * is also the right way to remove part of the used_space
595 * B+tree leaf list.
[da1bafb]596 */
597 bool cond = true;
598 while (cond) {
[56789125]599 ASSERT(!list_empty(&area->used_space.leaf_head));
[da1bafb]600
601 btree_node_t *node =
[6f4495f5]602 list_get_instance(area->used_space.leaf_head.prev,
603 btree_node_t, leaf_link);
[da1bafb]604
[56789125]605 if ((cond = (bool) node->keys)) {
[da1bafb]606 uintptr_t ptr = node->key[node->keys - 1];
607 size_t size =
[98000fb]608 (size_t) node->value[node->keys - 1];
[da1bafb]609 size_t i = 0;
610
[0b37882]611 if (overlaps(ptr, size << PAGE_WIDTH, area->base,
612 pages << PAGE_WIDTH)) {
[56789125]613
[0b37882]614 if (ptr + (size << PAGE_WIDTH) <= start_free) {
[56789125]615 /*
[6f4495f5]616 * The whole interval fits
617 * completely in the resized
618 * address space area.
[56789125]619 */
620 break;
621 }
[da1bafb]622
[56789125]623 /*
[6f4495f5]624 * Part of the interval corresponding
625 * to b and c overlaps with the resized
626 * address space area.
[56789125]627 */
[da1bafb]628
629 /* We are almost done */
630 cond = false;
631 i = (start_free - ptr) >> PAGE_WIDTH;
[6745592]632 if (!used_space_remove(area, start_free,
[da1bafb]633 size - i))
634 panic("Cannot remove used space.");
[56789125]635 } else {
636 /*
[6f4495f5]637 * The interval of used space can be
638 * completely removed.
[56789125]639 */
[da1bafb]640 if (!used_space_remove(area, ptr, size))
641 panic("Cannot remove used space.");
[56789125]642 }
[da1bafb]643
644 for (; i < size; i++) {
645 pte_t *pte = page_mapping_find(as, ptr +
[0b37882]646 (i << PAGE_WIDTH));
[da1bafb]647
648 ASSERT(pte);
649 ASSERT(PTE_VALID(pte));
650 ASSERT(PTE_PRESENT(pte));
651
652 if ((area->backend) &&
653 (area->backend->frame_free)) {
[0ee077ee]654 area->backend->frame_free(area,
[0b37882]655 ptr + (i << PAGE_WIDTH),
[6f4495f5]656 PTE_GET_FRAME(pte));
[8182031]657 }
[da1bafb]658
659 page_mapping_remove(as, ptr +
[0b37882]660 (i << PAGE_WIDTH));
[56789125]661 }
[df0103f7]662 }
663 }
[da1bafb]664
[df0103f7]665 /*
[5552d60]666 * Finish TLB shootdown sequence.
[df0103f7]667 */
[da1bafb]668
[0b37882]669 tlb_invalidate_pages(as->asid, area->base + (pages << PAGE_WIDTH),
[6f4495f5]670 area->pages - pages);
[da1bafb]671
[f1d1f5d3]672 /*
673 * Invalidate software translation caches (e.g. TSB on sparc64).
674 */
[6f4495f5]675 as_invalidate_translation_cache(as, area->base +
[0b37882]676 (pages << PAGE_WIDTH), area->pages - pages);
[402eda5]677 tlb_shootdown_finalize(ipl);
[31d8e10]678
[da1bafb]679 page_table_unlock(as, false);
[df0103f7]680 } else {
681 /*
682 * Growing the area.
683 * Check for overlaps with other address space areas.
684 */
[0b37882]685 if (!check_area_conflicts(as, address, pages, area)) {
[1068f6a]686 mutex_unlock(&area->lock);
[da1bafb]687 mutex_unlock(&as->lock);
[7242a78e]688 return EADDRNOTAVAIL;
[df0103f7]689 }
[da1bafb]690 }
691
[df0103f7]692 area->pages = pages;
693
[1068f6a]694 mutex_unlock(&area->lock);
695 mutex_unlock(&as->lock);
[da1bafb]696
[7242a78e]697 return 0;
698}
699
[e3ee9b9]700/** Remove reference to address space area share info.
701 *
702 * If the reference count drops to 0, the sh_info is deallocated.
703 *
704 * @param sh_info Pointer to address space area share info.
705 *
706 */
[7a0359b]707NO_TRACE static void sh_info_remove_reference(share_info_t *sh_info)
[e3ee9b9]708{
709 bool dealloc = false;
710
711 mutex_lock(&sh_info->lock);
712 ASSERT(sh_info->refcount);
713
714 if (--sh_info->refcount == 0) {
715 dealloc = true;
716 link_t *cur;
717
718 /*
719 * Now walk carefully the pagemap B+tree and free/remove
720 * reference from all frames found there.
721 */
722 for (cur = sh_info->pagemap.leaf_head.next;
723 cur != &sh_info->pagemap.leaf_head; cur = cur->next) {
724 btree_node_t *node
725 = list_get_instance(cur, btree_node_t, leaf_link);
726 btree_key_t i;
727
728 for (i = 0; i < node->keys; i++)
729 frame_free((uintptr_t) node->value[i]);
730 }
731
732 }
733 mutex_unlock(&sh_info->lock);
734
735 if (dealloc) {
736 btree_destroy(&sh_info->pagemap);
737 free(sh_info);
738 }
739}
740
[7242a78e]741/** Destroy address space area.
742 *
[da1bafb]743 * @param as Address space.
744 * @param address Address within the area to be deleted.
745 *
746 * @return Zero on success or a value from @ref errno.h on failure.
[7242a78e]747 *
748 */
[7f1c620]749int as_area_destroy(as_t *as, uintptr_t address)
[7242a78e]750{
[1068f6a]751 mutex_lock(&as->lock);
[da1bafb]752
753 as_area_t *area = find_area_and_lock(as, address);
[7242a78e]754 if (!area) {
[1068f6a]755 mutex_unlock(&as->lock);
[7242a78e]756 return ENOENT;
757 }
[da1bafb]758
759 uintptr_t base = area->base;
760
[c964521]761 page_table_lock(as, false);
[da1bafb]762
[5552d60]763 /*
764 * Start TLB shootdown sequence.
765 */
[402eda5]766 ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base,
767 area->pages);
[da1bafb]768
[567807b1]769 /*
770 * Visit only the pages mapped by used_space B+tree.
771 */
[da1bafb]772 link_t *cur;
[6f4495f5]773 for (cur = area->used_space.leaf_head.next;
774 cur != &area->used_space.leaf_head; cur = cur->next) {
[567807b1]775 btree_node_t *node;
[da1bafb]776 btree_key_t i;
[56789125]777
[f8d069e8]778 node = list_get_instance(cur, btree_node_t, leaf_link);
779 for (i = 0; i < node->keys; i++) {
[da1bafb]780 uintptr_t ptr = node->key[i];
781 size_t size;
[56789125]782
[da1bafb]783 for (size = 0; size < (size_t) node->value[i]; size++) {
[0b37882]784 pte_t *pte =
785 page_mapping_find(as, ptr + (size << PAGE_WIDTH));
[da1bafb]786
787 ASSERT(pte);
788 ASSERT(PTE_VALID(pte));
789 ASSERT(PTE_PRESENT(pte));
790
791 if ((area->backend) &&
792 (area->backend->frame_free)) {
793 area->backend->frame_free(area,
[0b37882]794 ptr + (size << PAGE_WIDTH), PTE_GET_FRAME(pte));
[56789125]795 }
[da1bafb]796
[0b37882]797 page_mapping_remove(as, ptr + (size << PAGE_WIDTH));
[7242a78e]798 }
799 }
800 }
[da1bafb]801
[7242a78e]802 /*
[5552d60]803 * Finish TLB shootdown sequence.
[7242a78e]804 */
[da1bafb]805
[f1d1f5d3]806 tlb_invalidate_pages(as->asid, area->base, area->pages);
[da1bafb]807
[f1d1f5d3]808 /*
[6f4495f5]809 * Invalidate potential software translation caches (e.g. TSB on
810 * sparc64).
[f1d1f5d3]811 */
812 as_invalidate_translation_cache(as, area->base, area->pages);
[402eda5]813 tlb_shootdown_finalize(ipl);
[da1bafb]814
[c964521]815 page_table_unlock(as, false);
[f1d1f5d3]816
[5552d60]817 btree_destroy(&area->used_space);
[da1bafb]818
[8d4f2ae]819 area->attributes |= AS_AREA_ATTR_PARTIAL;
[8182031]820
821 if (area->sh_info)
822 sh_info_remove_reference(area->sh_info);
[da1bafb]823
[1068f6a]824 mutex_unlock(&area->lock);
[da1bafb]825
[7242a78e]826 /*
827 * Remove the empty area from address space.
828 */
[f1d1f5d3]829 btree_remove(&as->as_area_btree, base, NULL);
[7242a78e]830
[8d4f2ae]831 free(area);
832
[f1d1f5d3]833 mutex_unlock(&as->lock);
[7242a78e]834 return 0;
[df0103f7]835}
836
[8d6bc2d5]837/** Share address space area with another or the same address space.
[df0103f7]838 *
[0ee077ee]839 * Address space area mapping is shared with a new address space area.
840 * If the source address space area has not been shared so far,
841 * a new sh_info is created. The new address space area simply gets the
842 * sh_info of the source area. The process of duplicating the
843 * mapping is done through the backend share function.
[da1bafb]844 *
845 * @param src_as Pointer to source address space.
846 * @param src_base Base address of the source address space area.
847 * @param acc_size Expected size of the source area.
848 * @param dst_as Pointer to destination address space.
849 * @param dst_base Target base address.
[fd4d8c0]850 * @param dst_flags_mask Destination address space area flags mask.
[df0103f7]851 *
[da1bafb]852 * @return Zero on success.
853 * @return ENOENT if there is no such task or such address space.
854 * @return EPERM if there was a problem in accepting the area.
855 * @return ENOMEM if there was a problem in allocating destination
856 * address space area.
857 * @return ENOTSUP if the address space area backend does not support
858 * sharing.
859 *
[df0103f7]860 */
[7f1c620]861int as_area_share(as_t *src_as, uintptr_t src_base, size_t acc_size,
[da1bafb]862 as_t *dst_as, uintptr_t dst_base, unsigned int dst_flags_mask)
[df0103f7]863{
[1068f6a]864 mutex_lock(&src_as->lock);
[da1bafb]865 as_area_t *src_area = find_area_and_lock(src_as, src_base);
[a9e8b39]866 if (!src_area) {
[6fa476f7]867 /*
868 * Could not find the source address space area.
869 */
[1068f6a]870 mutex_unlock(&src_as->lock);
[6fa476f7]871 return ENOENT;
872 }
[da1bafb]873
874 if ((!src_area->backend) || (!src_area->backend->share)) {
[8d6bc2d5]875 /*
[f47fd19]876 * There is no backend or the backend does not
[0ee077ee]877 * know how to share the area.
[8d6bc2d5]878 */
879 mutex_unlock(&src_area->lock);
880 mutex_unlock(&src_as->lock);
881 return ENOTSUP;
882 }
883
[0b37882]884 size_t src_size = src_area->pages << PAGE_WIDTH;
[da1bafb]885 unsigned int src_flags = src_area->flags;
886 mem_backend_t *src_backend = src_area->backend;
887 mem_backend_data_t src_backend_data = src_area->backend_data;
888
[1ec1fd8]889 /* Share the cacheable flag from the original mapping */
890 if (src_flags & AS_AREA_CACHEABLE)
891 dst_flags_mask |= AS_AREA_CACHEABLE;
[da1bafb]892
893 if ((src_size != acc_size) ||
894 ((src_flags & dst_flags_mask) != dst_flags_mask)) {
[8d6bc2d5]895 mutex_unlock(&src_area->lock);
896 mutex_unlock(&src_as->lock);
[df0103f7]897 return EPERM;
898 }
[da1bafb]899
[8d6bc2d5]900 /*
901 * Now we are committed to sharing the area.
[8440473]902 * First, prepare the area for sharing.
[8d6bc2d5]903 * Then it will be safe to unlock it.
904 */
[da1bafb]905 share_info_t *sh_info = src_area->sh_info;
[8d6bc2d5]906 if (!sh_info) {
907 sh_info = (share_info_t *) malloc(sizeof(share_info_t), 0);
[08a19ba]908 mutex_initialize(&sh_info->lock, MUTEX_PASSIVE);
[8d6bc2d5]909 sh_info->refcount = 2;
910 btree_create(&sh_info->pagemap);
911 src_area->sh_info = sh_info;
[da1bafb]912
[c0697c4c]913 /*
914 * Call the backend to setup sharing.
915 */
916 src_area->backend->share(src_area);
[8d6bc2d5]917 } else {
918 mutex_lock(&sh_info->lock);
919 sh_info->refcount++;
920 mutex_unlock(&sh_info->lock);
921 }
[da1bafb]922
[8d6bc2d5]923 mutex_unlock(&src_area->lock);
924 mutex_unlock(&src_as->lock);
[da1bafb]925
[df0103f7]926 /*
[a9e8b39]927 * Create copy of the source address space area.
928 * The destination area is created with AS_AREA_ATTR_PARTIAL
929 * attribute set which prevents race condition with
930 * preliminary as_page_fault() calls.
[fd4d8c0]931 * The flags of the source area are masked against dst_flags_mask
932 * to support sharing in less privileged mode.
[df0103f7]933 */
[da1bafb]934 as_area_t *dst_area = as_area_create(dst_as, dst_flags_mask, src_size,
935 dst_base, AS_AREA_ATTR_PARTIAL, src_backend, &src_backend_data);
[a9e8b39]936 if (!dst_area) {
[df0103f7]937 /*
938 * Destination address space area could not be created.
939 */
[8d6bc2d5]940 sh_info_remove_reference(sh_info);
941
[df0103f7]942 return ENOMEM;
943 }
[da1bafb]944
[a9e8b39]945 /*
946 * Now the destination address space area has been
947 * fully initialized. Clear the AS_AREA_ATTR_PARTIAL
[8d6bc2d5]948 * attribute and set the sh_info.
[da1bafb]949 */
950 mutex_lock(&dst_as->lock);
[1068f6a]951 mutex_lock(&dst_area->lock);
[a9e8b39]952 dst_area->attributes &= ~AS_AREA_ATTR_PARTIAL;
[8d6bc2d5]953 dst_area->sh_info = sh_info;
[1068f6a]954 mutex_unlock(&dst_area->lock);
[da1bafb]955 mutex_unlock(&dst_as->lock);
956
[df0103f7]957 return 0;
958}
959
[fb84455]960/** Check access mode for address space area.
961 *
[da1bafb]962 * @param area Address space area.
963 * @param access Access mode.
964 *
965 * @return False if access violates area's permissions, true
966 * otherwise.
[fb84455]967 *
968 */
[97bdb4a]969NO_TRACE bool as_area_check_access(as_area_t *area, pf_access_t access)
[fb84455]970{
[fc47885]971 ASSERT(mutex_locked(&area->lock));
972
[fb84455]973 int flagmap[] = {
974 [PF_ACCESS_READ] = AS_AREA_READ,
975 [PF_ACCESS_WRITE] = AS_AREA_WRITE,
976 [PF_ACCESS_EXEC] = AS_AREA_EXEC
977 };
[da1bafb]978
[fb84455]979 if (!(area->flags & flagmap[access]))
980 return false;
981
982 return true;
983}
984
[e3ee9b9]985/** Convert address space area flags to page flags.
986 *
987 * @param aflags Flags of some address space area.
988 *
989 * @return Flags to be passed to page_mapping_insert().
990 *
991 */
[7a0359b]992NO_TRACE static unsigned int area_flags_to_page_flags(unsigned int aflags)
[e3ee9b9]993{
994 unsigned int flags = PAGE_USER | PAGE_PRESENT;
995
996 if (aflags & AS_AREA_READ)
997 flags |= PAGE_READ;
998
999 if (aflags & AS_AREA_WRITE)
1000 flags |= PAGE_WRITE;
1001
1002 if (aflags & AS_AREA_EXEC)
1003 flags |= PAGE_EXEC;
1004
1005 if (aflags & AS_AREA_CACHEABLE)
1006 flags |= PAGE_CACHEABLE;
1007
1008 return flags;
1009}
1010
[6745592]1011/** Change adress space area flags.
[c98e6ee]1012 *
1013 * The idea is to have the same data, but with a different access mode.
1014 * This is needed e.g. for writing code into memory and then executing it.
1015 * In order for this to work properly, this may copy the data
1016 * into private anonymous memory (unless it's already there).
1017 *
[76fca31]1018 * @param as Address space.
1019 * @param flags Flags of the area memory.
1020 * @param address Address within the area to be changed.
1021 *
1022 * @return Zero on success or a value from @ref errno.h on failure.
[c98e6ee]1023 *
1024 */
[da1bafb]1025int as_area_change_flags(as_t *as, unsigned int flags, uintptr_t address)
[c98e6ee]1026{
1027 /* Flags for the new memory mapping */
[da1bafb]1028 unsigned int page_flags = area_flags_to_page_flags(flags);
1029
[c98e6ee]1030 mutex_lock(&as->lock);
[da1bafb]1031
1032 as_area_t *area = find_area_and_lock(as, address);
[c98e6ee]1033 if (!area) {
1034 mutex_unlock(&as->lock);
1035 return ENOENT;
1036 }
[da1bafb]1037
[76fca31]1038 if ((area->sh_info) || (area->backend != &anon_backend)) {
[c98e6ee]1039 /* Copying shared areas not supported yet */
1040 /* Copying non-anonymous memory not supported yet */
1041 mutex_unlock(&area->lock);
1042 mutex_unlock(&as->lock);
1043 return ENOTSUP;
1044 }
[da1bafb]1045
[c98e6ee]1046 /*
1047 * Compute total number of used pages in the used_space B+tree
1048 */
[da1bafb]1049 size_t used_pages = 0;
1050 link_t *cur;
1051
[c98e6ee]1052 for (cur = area->used_space.leaf_head.next;
1053 cur != &area->used_space.leaf_head; cur = cur->next) {
[da1bafb]1054 btree_node_t *node
1055 = list_get_instance(cur, btree_node_t, leaf_link);
1056 btree_key_t i;
[c98e6ee]1057
[da1bafb]1058 for (i = 0; i < node->keys; i++)
[98000fb]1059 used_pages += (size_t) node->value[i];
[c98e6ee]1060 }
[da1bafb]1061
[c98e6ee]1062 /* An array for storing frame numbers */
[da1bafb]1063 uintptr_t *old_frame = malloc(used_pages * sizeof(uintptr_t), 0);
1064
[c964521]1065 page_table_lock(as, false);
[da1bafb]1066
[c98e6ee]1067 /*
1068 * Start TLB shootdown sequence.
1069 */
[402eda5]1070 ipl_t ipl = tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base,
1071 area->pages);
[da1bafb]1072
[c98e6ee]1073 /*
1074 * Remove used pages from page tables and remember their frame
1075 * numbers.
1076 */
[da1bafb]1077 size_t frame_idx = 0;
1078
[c98e6ee]1079 for (cur = area->used_space.leaf_head.next;
1080 cur != &area->used_space.leaf_head; cur = cur->next) {
[da1bafb]1081 btree_node_t *node
1082 = list_get_instance(cur, btree_node_t, leaf_link);
1083 btree_key_t i;
[c98e6ee]1084
1085 for (i = 0; i < node->keys; i++) {
[da1bafb]1086 uintptr_t ptr = node->key[i];
1087 size_t size;
[c98e6ee]1088
[da1bafb]1089 for (size = 0; size < (size_t) node->value[i]; size++) {
[0b37882]1090 pte_t *pte =
1091 page_mapping_find(as, ptr + (size << PAGE_WIDTH));
[da1bafb]1092
1093 ASSERT(pte);
1094 ASSERT(PTE_VALID(pte));
1095 ASSERT(PTE_PRESENT(pte));
1096
[c98e6ee]1097 old_frame[frame_idx++] = PTE_GET_FRAME(pte);
[da1bafb]1098
[c98e6ee]1099 /* Remove old mapping */
[0b37882]1100 page_mapping_remove(as, ptr + (size << PAGE_WIDTH));
[c98e6ee]1101 }
1102 }
1103 }
[da1bafb]1104
[c98e6ee]1105 /*
1106 * Finish TLB shootdown sequence.
1107 */
[da1bafb]1108
[c98e6ee]1109 tlb_invalidate_pages(as->asid, area->base, area->pages);
[76fca31]1110
[c98e6ee]1111 /*
1112 * Invalidate potential software translation caches (e.g. TSB on
1113 * sparc64).
1114 */
1115 as_invalidate_translation_cache(as, area->base, area->pages);
[402eda5]1116 tlb_shootdown_finalize(ipl);
[da1bafb]1117
[c964521]1118 page_table_unlock(as, false);
[da1bafb]1119
[ae7f6fb]1120 /*
1121 * Set the new flags.
1122 */
1123 area->flags = flags;
[da1bafb]1124
[c98e6ee]1125 /*
1126 * Map pages back in with new flags. This step is kept separate
[6745592]1127 * so that the memory area could not be accesed with both the old and
1128 * the new flags at once.
[c98e6ee]1129 */
1130 frame_idx = 0;
[da1bafb]1131
[c98e6ee]1132 for (cur = area->used_space.leaf_head.next;
1133 cur != &area->used_space.leaf_head; cur = cur->next) {
[da1bafb]1134 btree_node_t *node
1135 = list_get_instance(cur, btree_node_t, leaf_link);
1136 btree_key_t i;
[c98e6ee]1137
1138 for (i = 0; i < node->keys; i++) {
[da1bafb]1139 uintptr_t ptr = node->key[i];
1140 size_t size;
[c98e6ee]1141
[da1bafb]1142 for (size = 0; size < (size_t) node->value[i]; size++) {
[c98e6ee]1143 page_table_lock(as, false);
[da1bafb]1144
[c98e6ee]1145 /* Insert the new mapping */
[0b37882]1146 page_mapping_insert(as, ptr + (size << PAGE_WIDTH),
[c98e6ee]1147 old_frame[frame_idx++], page_flags);
[da1bafb]1148
[c98e6ee]1149 page_table_unlock(as, false);
1150 }
1151 }
1152 }
[da1bafb]1153
[c98e6ee]1154 free(old_frame);
[da1bafb]1155
[c98e6ee]1156 mutex_unlock(&area->lock);
1157 mutex_unlock(&as->lock);
[da1bafb]1158
[c98e6ee]1159 return 0;
1160}
1161
[20d50a1]1162/** Handle page fault within the current address space.
1163 *
[6745592]1164 * This is the high-level page fault handler. It decides whether the page fault
1165 * can be resolved by any backend and if so, it invokes the backend to resolve
1166 * the page fault.
[8182031]1167 *
[20d50a1]1168 * Interrupts are assumed disabled.
1169 *
[da1bafb]1170 * @param page Faulting page.
1171 * @param access Access mode that caused the page fault (i.e.
1172 * read/write/exec).
1173 * @param istate Pointer to the interrupted state.
1174 *
1175 * @return AS_PF_FAULT on page fault.
1176 * @return AS_PF_OK on success.
1177 * @return AS_PF_DEFER if the fault was caused by copy_to_uspace()
1178 * or copy_from_uspace().
[20d50a1]1179 *
1180 */
[7f1c620]1181int as_page_fault(uintptr_t page, pf_access_t access, istate_t *istate)
[20d50a1]1182{
[1068f6a]1183 if (!THREAD)
[8182031]1184 return AS_PF_FAULT;
[7af8c0e]1185
1186 if (!AS)
1187 return AS_PF_FAULT;
1188
[1068f6a]1189 mutex_lock(&AS->lock);
[da1bafb]1190 as_area_t *area = find_area_and_lock(AS, page);
[20d50a1]1191 if (!area) {
1192 /*
1193 * No area contained mapping for 'page'.
1194 * Signal page fault to low-level handler.
1195 */
[1068f6a]1196 mutex_unlock(&AS->lock);
[e3c762cd]1197 goto page_fault;
[20d50a1]1198 }
[da1bafb]1199
[a9e8b39]1200 if (area->attributes & AS_AREA_ATTR_PARTIAL) {
1201 /*
1202 * The address space area is not fully initialized.
1203 * Avoid possible race by returning error.
1204 */
[1068f6a]1205 mutex_unlock(&area->lock);
1206 mutex_unlock(&AS->lock);
[da1bafb]1207 goto page_fault;
[a9e8b39]1208 }
[da1bafb]1209
1210 if ((!area->backend) || (!area->backend->page_fault)) {
[8182031]1211 /*
1212 * The address space area is not backed by any backend
1213 * or the backend cannot handle page faults.
1214 */
1215 mutex_unlock(&area->lock);
1216 mutex_unlock(&AS->lock);
[da1bafb]1217 goto page_fault;
[8182031]1218 }
[da1bafb]1219
[2299914]1220 page_table_lock(AS, false);
1221
1222 /*
[6745592]1223 * To avoid race condition between two page faults on the same address,
1224 * we need to make sure the mapping has not been already inserted.
[2299914]1225 */
[da1bafb]1226 pte_t *pte;
[2299914]1227 if ((pte = page_mapping_find(AS, page))) {
1228 if (PTE_PRESENT(pte)) {
[fb84455]1229 if (((access == PF_ACCESS_READ) && PTE_READABLE(pte)) ||
[6f4495f5]1230 (access == PF_ACCESS_WRITE && PTE_WRITABLE(pte)) ||
1231 (access == PF_ACCESS_EXEC && PTE_EXECUTABLE(pte))) {
[fb84455]1232 page_table_unlock(AS, false);
1233 mutex_unlock(&area->lock);
1234 mutex_unlock(&AS->lock);
1235 return AS_PF_OK;
1236 }
[2299914]1237 }
1238 }
[20d50a1]1239
1240 /*
[8182031]1241 * Resort to the backend page fault handler.
[20d50a1]1242 */
[0ee077ee]1243 if (area->backend->page_fault(area, page, access) != AS_PF_OK) {
[8182031]1244 page_table_unlock(AS, false);
1245 mutex_unlock(&area->lock);
1246 mutex_unlock(&AS->lock);
1247 goto page_fault;
1248 }
[20d50a1]1249
[8182031]1250 page_table_unlock(AS, false);
[1068f6a]1251 mutex_unlock(&area->lock);
1252 mutex_unlock(&AS->lock);
[e3c762cd]1253 return AS_PF_OK;
[da1bafb]1254
[e3c762cd]1255page_fault:
1256 if (THREAD->in_copy_from_uspace) {
1257 THREAD->in_copy_from_uspace = false;
[6f4495f5]1258 istate_set_retaddr(istate,
1259 (uintptr_t) &memcpy_from_uspace_failover_address);
[e3c762cd]1260 } else if (THREAD->in_copy_to_uspace) {
1261 THREAD->in_copy_to_uspace = false;
[6f4495f5]1262 istate_set_retaddr(istate,
1263 (uintptr_t) &memcpy_to_uspace_failover_address);
[e3c762cd]1264 } else {
1265 return AS_PF_FAULT;
1266 }
[da1bafb]1267
[e3c762cd]1268 return AS_PF_DEFER;
[20d50a1]1269}
1270
[7e4e532]1271/** Switch address spaces.
[1068f6a]1272 *
1273 * Note that this function cannot sleep as it is essentially a part of
[879585a3]1274 * scheduling. Sleeping here would lead to deadlock on wakeup. Another
1275 * thing which is forbidden in this context is locking the address space.
[20d50a1]1276 *
[31d8e10]1277 * When this function is enetered, no spinlocks may be held.
1278 *
[da1bafb]1279 * @param old Old address space or NULL.
1280 * @param new New address space.
1281 *
[20d50a1]1282 */
[80bcaed]1283void as_switch(as_t *old_as, as_t *new_as)
[20d50a1]1284{
[31d8e10]1285 DEADLOCK_PROBE_INIT(p_asidlock);
1286 preemption_disable();
[da1bafb]1287
[31d8e10]1288retry:
1289 (void) interrupts_disable();
1290 if (!spinlock_trylock(&asidlock)) {
[da1bafb]1291 /*
[31d8e10]1292 * Avoid deadlock with TLB shootdown.
1293 * We can enable interrupts here because
1294 * preemption is disabled. We should not be
1295 * holding any other lock.
1296 */
1297 (void) interrupts_enable();
1298 DEADLOCK_PROBE(p_asidlock, DEADLOCK_THRESHOLD);
1299 goto retry;
1300 }
1301 preemption_enable();
[da1bafb]1302
[7e4e532]1303 /*
1304 * First, take care of the old address space.
[da1bafb]1305 */
[80bcaed]1306 if (old_as) {
1307 ASSERT(old_as->cpu_refcount);
[da1bafb]1308
1309 if ((--old_as->cpu_refcount == 0) && (old_as != AS_KERNEL)) {
[7e4e532]1310 /*
1311 * The old address space is no longer active on
1312 * any processor. It can be appended to the
1313 * list of inactive address spaces with assigned
1314 * ASID.
1315 */
[2057572]1316 ASSERT(old_as->asid != ASID_INVALID);
[da1bafb]1317
[2057572]1318 list_append(&old_as->inactive_as_with_asid_link,
1319 &inactive_as_with_asid_head);
[7e4e532]1320 }
[da1bafb]1321
[57da95c]1322 /*
1323 * Perform architecture-specific tasks when the address space
1324 * is being removed from the CPU.
1325 */
[80bcaed]1326 as_deinstall_arch(old_as);
[7e4e532]1327 }
[da1bafb]1328
[7e4e532]1329 /*
1330 * Second, prepare the new address space.
1331 */
[80bcaed]1332 if ((new_as->cpu_refcount++ == 0) && (new_as != AS_KERNEL)) {
[879585a3]1333 if (new_as->asid != ASID_INVALID)
[80bcaed]1334 list_remove(&new_as->inactive_as_with_asid_link);
[879585a3]1335 else
1336 new_as->asid = asid_get();
[7e4e532]1337 }
[da1bafb]1338
[80bcaed]1339#ifdef AS_PAGE_TABLE
1340 SET_PTL0_ADDRESS(new_as->genarch.page_table);
1341#endif
[7e4e532]1342
[20d50a1]1343 /*
1344 * Perform architecture-specific steps.
[4512d7e]1345 * (e.g. write ASID to hardware register etc.)
[20d50a1]1346 */
[80bcaed]1347 as_install_arch(new_as);
[da1bafb]1348
[879585a3]1349 spinlock_unlock(&asidlock);
[20d50a1]1350
[80bcaed]1351 AS = new_as;
[20d50a1]1352}
[6a3c9a7]1353
[df0103f7]1354/** Compute flags for virtual address translation subsytem.
1355 *
[da1bafb]1356 * @param area Address space area.
1357 *
1358 * @return Flags to be used in page_mapping_insert().
[df0103f7]1359 *
1360 */
[97bdb4a]1361NO_TRACE unsigned int as_area_get_flags(as_area_t *area)
[df0103f7]1362{
[1d432f9]1363 ASSERT(mutex_locked(&area->lock));
[fc47885]1364
[da1bafb]1365 return area_flags_to_page_flags(area->flags);
[df0103f7]1366}
1367
[ef67bab]1368/** Create page table.
1369 *
[6745592]1370 * Depending on architecture, create either address space private or global page
1371 * table.
[ef67bab]1372 *
[da1bafb]1373 * @param flags Flags saying whether the page table is for the kernel
1374 * address space.
1375 *
1376 * @return First entry of the page table.
[ef67bab]1377 *
1378 */
[97bdb4a]1379NO_TRACE pte_t *page_table_create(unsigned int flags)
[ef67bab]1380{
[bd1deed]1381 ASSERT(as_operations);
1382 ASSERT(as_operations->page_table_create);
1383
1384 return as_operations->page_table_create(flags);
[ef67bab]1385}
[d3e7ff4]1386
[482826d]1387/** Destroy page table.
1388 *
1389 * Destroy page table in architecture specific way.
1390 *
[da1bafb]1391 * @param page_table Physical address of PTL0.
1392 *
[482826d]1393 */
[97bdb4a]1394NO_TRACE void page_table_destroy(pte_t *page_table)
[482826d]1395{
[bd1deed]1396 ASSERT(as_operations);
1397 ASSERT(as_operations->page_table_destroy);
1398
1399 as_operations->page_table_destroy(page_table);
[482826d]1400}
1401
[2299914]1402/** Lock page table.
1403 *
1404 * This function should be called before any page_mapping_insert(),
1405 * page_mapping_remove() and page_mapping_find().
[da1bafb]1406 *
[2299914]1407 * Locking order is such that address space areas must be locked
1408 * prior to this call. Address space can be locked prior to this
1409 * call in which case the lock argument is false.
1410 *
[da1bafb]1411 * @param as Address space.
1412 * @param lock If false, do not attempt to lock as->lock.
1413 *
[2299914]1414 */
[97bdb4a]1415NO_TRACE void page_table_lock(as_t *as, bool lock)
[2299914]1416{
1417 ASSERT(as_operations);
1418 ASSERT(as_operations->page_table_lock);
[bd1deed]1419
[2299914]1420 as_operations->page_table_lock(as, lock);
1421}
1422
1423/** Unlock page table.
1424 *
[da1bafb]1425 * @param as Address space.
1426 * @param unlock If false, do not attempt to unlock as->lock.
1427 *
[2299914]1428 */
[97bdb4a]1429NO_TRACE void page_table_unlock(as_t *as, bool unlock)
[2299914]1430{
1431 ASSERT(as_operations);
1432 ASSERT(as_operations->page_table_unlock);
[bd1deed]1433
[2299914]1434 as_operations->page_table_unlock(as, unlock);
1435}
1436
[ada559c]1437/** Test whether page tables are locked.
1438 *
[e3ee9b9]1439 * @param as Address space where the page tables belong.
[ada559c]1440 *
[e3ee9b9]1441 * @return True if the page tables belonging to the address soace
1442 * are locked, otherwise false.
[ada559c]1443 */
[97bdb4a]1444NO_TRACE bool page_table_locked(as_t *as)
[ada559c]1445{
1446 ASSERT(as_operations);
1447 ASSERT(as_operations->page_table_locked);
1448
1449 return as_operations->page_table_locked(as);
1450}
1451
[b878df3]1452/** Return size of the address space area with given base.
1453 *
[1d432f9]1454 * @param base Arbitrary address inside the address space area.
[da1bafb]1455 *
1456 * @return Size of the address space area in bytes or zero if it
1457 * does not exist.
[b878df3]1458 *
1459 */
1460size_t as_area_get_size(uintptr_t base)
[7c23af9]1461{
1462 size_t size;
[da1bafb]1463
[1d432f9]1464 page_table_lock(AS, true);
[da1bafb]1465 as_area_t *src_area = find_area_and_lock(AS, base);
1466
[6745592]1467 if (src_area) {
[0b37882]1468 size = src_area->pages << PAGE_WIDTH;
[1068f6a]1469 mutex_unlock(&src_area->lock);
[da1bafb]1470 } else
[7c23af9]1471 size = 0;
[da1bafb]1472
[1d432f9]1473 page_table_unlock(AS, true);
[7c23af9]1474 return size;
1475}
1476
[25bf215]1477/** Mark portion of address space area as used.
1478 *
1479 * The address space area must be already locked.
1480 *
[da1bafb]1481 * @param area Address space area.
1482 * @param page First page to be marked.
1483 * @param count Number of page to be marked.
1484 *
[fc47885]1485 * @return False on failure or true on success.
[25bf215]1486 *
1487 */
[fc47885]1488bool used_space_insert(as_area_t *area, uintptr_t page, size_t count)
[25bf215]1489{
[1d432f9]1490 ASSERT(mutex_locked(&area->lock));
[25bf215]1491 ASSERT(page == ALIGN_DOWN(page, PAGE_SIZE));
1492 ASSERT(count);
[da1bafb]1493
1494 btree_node_t *leaf;
1495 size_t pages = (size_t) btree_search(&area->used_space, page, &leaf);
[25bf215]1496 if (pages) {
1497 /*
1498 * We hit the beginning of some used space.
1499 */
[fc47885]1500 return false;
[25bf215]1501 }
[da1bafb]1502
[a6cb8cb]1503 if (!leaf->keys) {
[da1bafb]1504 btree_insert(&area->used_space, page, (void *) count, leaf);
[fc47885]1505 goto success;
[a6cb8cb]1506 }
[da1bafb]1507
1508 btree_node_t *node = btree_leaf_node_left_neighbour(&area->used_space, leaf);
[25bf215]1509 if (node) {
[6f4495f5]1510 uintptr_t left_pg = node->key[node->keys - 1];
1511 uintptr_t right_pg = leaf->key[0];
[98000fb]1512 size_t left_cnt = (size_t) node->value[node->keys - 1];
1513 size_t right_cnt = (size_t) leaf->value[0];
[25bf215]1514
1515 /*
1516 * Examine the possibility that the interval fits
1517 * somewhere between the rightmost interval of
1518 * the left neigbour and the first interval of the leaf.
1519 */
[da1bafb]1520
[25bf215]1521 if (page >= right_pg) {
1522 /* Do nothing. */
[0b37882]1523 } else if (overlaps(page, count << PAGE_WIDTH, left_pg,
1524 left_cnt << PAGE_WIDTH)) {
[25bf215]1525 /* The interval intersects with the left interval. */
[fc47885]1526 return false;
[0b37882]1527 } else if (overlaps(page, count << PAGE_WIDTH, right_pg,
1528 right_cnt << PAGE_WIDTH)) {
[25bf215]1529 /* The interval intersects with the right interval. */
[fc47885]1530 return false;
[0b37882]1531 } else if ((page == left_pg + (left_cnt << PAGE_WIDTH)) &&
1532 (page + (count << PAGE_WIDTH) == right_pg)) {
[6f4495f5]1533 /*
1534 * The interval can be added by merging the two already
1535 * present intervals.
1536 */
[56789125]1537 node->value[node->keys - 1] += count + right_cnt;
[da1bafb]1538 btree_remove(&area->used_space, right_pg, leaf);
[fc47885]1539 goto success;
[0b37882]1540 } else if (page == left_pg + (left_cnt << PAGE_WIDTH)) {
[da1bafb]1541 /*
[6f4495f5]1542 * The interval can be added by simply growing the left
1543 * interval.
1544 */
[56789125]1545 node->value[node->keys - 1] += count;
[fc47885]1546 goto success;
[0b37882]1547 } else if (page + (count << PAGE_WIDTH) == right_pg) {
[25bf215]1548 /*
[6f4495f5]1549 * The interval can be addded by simply moving base of
1550 * the right interval down and increasing its size
1551 * accordingly.
[25bf215]1552 */
[56789125]1553 leaf->value[0] += count;
[25bf215]1554 leaf->key[0] = page;
[fc47885]1555 goto success;
[25bf215]1556 } else {
1557 /*
1558 * The interval is between both neigbouring intervals,
1559 * but cannot be merged with any of them.
1560 */
[da1bafb]1561 btree_insert(&area->used_space, page, (void *) count,
[6f4495f5]1562 leaf);
[fc47885]1563 goto success;
[25bf215]1564 }
1565 } else if (page < leaf->key[0]) {
[7f1c620]1566 uintptr_t right_pg = leaf->key[0];
[98000fb]1567 size_t right_cnt = (size_t) leaf->value[0];
[da1bafb]1568
[25bf215]1569 /*
[6f4495f5]1570 * Investigate the border case in which the left neighbour does
1571 * not exist but the interval fits from the left.
[25bf215]1572 */
[da1bafb]1573
[0b37882]1574 if (overlaps(page, count << PAGE_WIDTH, right_pg,
1575 right_cnt << PAGE_WIDTH)) {
[25bf215]1576 /* The interval intersects with the right interval. */
[fc47885]1577 return false;
[0b37882]1578 } else if (page + (count << PAGE_WIDTH) == right_pg) {
[25bf215]1579 /*
[6f4495f5]1580 * The interval can be added by moving the base of the
1581 * right interval down and increasing its size
1582 * accordingly.
[25bf215]1583 */
1584 leaf->key[0] = page;
[56789125]1585 leaf->value[0] += count;
[fc47885]1586 goto success;
[25bf215]1587 } else {
1588 /*
1589 * The interval doesn't adjoin with the right interval.
1590 * It must be added individually.
1591 */
[da1bafb]1592 btree_insert(&area->used_space, page, (void *) count,
[6f4495f5]1593 leaf);
[fc47885]1594 goto success;
[25bf215]1595 }
1596 }
[da1bafb]1597
1598 node = btree_leaf_node_right_neighbour(&area->used_space, leaf);
[25bf215]1599 if (node) {
[6f4495f5]1600 uintptr_t left_pg = leaf->key[leaf->keys - 1];
1601 uintptr_t right_pg = node->key[0];
[98000fb]1602 size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
1603 size_t right_cnt = (size_t) node->value[0];
[25bf215]1604
1605 /*
1606 * Examine the possibility that the interval fits
1607 * somewhere between the leftmost interval of
1608 * the right neigbour and the last interval of the leaf.
1609 */
[da1bafb]1610
[25bf215]1611 if (page < left_pg) {
1612 /* Do nothing. */
[0b37882]1613 } else if (overlaps(page, count << PAGE_WIDTH, left_pg,
1614 left_cnt << PAGE_WIDTH)) {
[25bf215]1615 /* The interval intersects with the left interval. */
[fc47885]1616 return false;
[0b37882]1617 } else if (overlaps(page, count << PAGE_WIDTH, right_pg,
1618 right_cnt << PAGE_WIDTH)) {
[25bf215]1619 /* The interval intersects with the right interval. */
[fc47885]1620 return false;
[0b37882]1621 } else if ((page == left_pg + (left_cnt << PAGE_WIDTH)) &&
1622 (page + (count << PAGE_WIDTH) == right_pg)) {
[6f4495f5]1623 /*
1624 * The interval can be added by merging the two already
1625 * present intervals.
[da1bafb]1626 */
[56789125]1627 leaf->value[leaf->keys - 1] += count + right_cnt;
[da1bafb]1628 btree_remove(&area->used_space, right_pg, node);
[fc47885]1629 goto success;
[0b37882]1630 } else if (page == left_pg + (left_cnt << PAGE_WIDTH)) {
[6f4495f5]1631 /*
1632 * The interval can be added by simply growing the left
1633 * interval.
[da1bafb]1634 */
[fc47885]1635 leaf->value[leaf->keys - 1] += count;
1636 goto success;
[0b37882]1637 } else if (page + (count << PAGE_WIDTH) == right_pg) {
[25bf215]1638 /*
[6f4495f5]1639 * The interval can be addded by simply moving base of
1640 * the right interval down and increasing its size
1641 * accordingly.
[25bf215]1642 */
[56789125]1643 node->value[0] += count;
[25bf215]1644 node->key[0] = page;
[fc47885]1645 goto success;
[25bf215]1646 } else {
1647 /*
1648 * The interval is between both neigbouring intervals,
1649 * but cannot be merged with any of them.
1650 */
[da1bafb]1651 btree_insert(&area->used_space, page, (void *) count,
[6f4495f5]1652 leaf);
[fc47885]1653 goto success;
[25bf215]1654 }
1655 } else if (page >= leaf->key[leaf->keys - 1]) {
[7f1c620]1656 uintptr_t left_pg = leaf->key[leaf->keys - 1];
[98000fb]1657 size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
[da1bafb]1658
[25bf215]1659 /*
[6f4495f5]1660 * Investigate the border case in which the right neighbour
1661 * does not exist but the interval fits from the right.
[25bf215]1662 */
[da1bafb]1663
[0b37882]1664 if (overlaps(page, count << PAGE_WIDTH, left_pg,
1665 left_cnt << PAGE_WIDTH)) {
[56789125]1666 /* The interval intersects with the left interval. */
[fc47885]1667 return false;
[0b37882]1668 } else if (left_pg + (left_cnt << PAGE_WIDTH) == page) {
[6f4495f5]1669 /*
1670 * The interval can be added by growing the left
1671 * interval.
1672 */
[56789125]1673 leaf->value[leaf->keys - 1] += count;
[fc47885]1674 goto success;
[25bf215]1675 } else {
1676 /*
1677 * The interval doesn't adjoin with the left interval.
1678 * It must be added individually.
1679 */
[da1bafb]1680 btree_insert(&area->used_space, page, (void *) count,
[6f4495f5]1681 leaf);
[fc47885]1682 goto success;
[25bf215]1683 }
1684 }
1685
1686 /*
[6f4495f5]1687 * Note that if the algorithm made it thus far, the interval can fit
1688 * only between two other intervals of the leaf. The two border cases
1689 * were already resolved.
[25bf215]1690 */
[da1bafb]1691 btree_key_t i;
[25bf215]1692 for (i = 1; i < leaf->keys; i++) {
1693 if (page < leaf->key[i]) {
[6f4495f5]1694 uintptr_t left_pg = leaf->key[i - 1];
1695 uintptr_t right_pg = leaf->key[i];
[98000fb]1696 size_t left_cnt = (size_t) leaf->value[i - 1];
1697 size_t right_cnt = (size_t) leaf->value[i];
[da1bafb]1698
[25bf215]1699 /*
1700 * The interval fits between left_pg and right_pg.
1701 */
[da1bafb]1702
[0b37882]1703 if (overlaps(page, count << PAGE_WIDTH, left_pg,
1704 left_cnt << PAGE_WIDTH)) {
[6f4495f5]1705 /*
1706 * The interval intersects with the left
1707 * interval.
1708 */
[fc47885]1709 return false;
[0b37882]1710 } else if (overlaps(page, count << PAGE_WIDTH, right_pg,
1711 right_cnt << PAGE_WIDTH)) {
[6f4495f5]1712 /*
1713 * The interval intersects with the right
1714 * interval.
1715 */
[fc47885]1716 return false;
[0b37882]1717 } else if ((page == left_pg + (left_cnt << PAGE_WIDTH)) &&
1718 (page + (count << PAGE_WIDTH) == right_pg)) {
[6f4495f5]1719 /*
1720 * The interval can be added by merging the two
1721 * already present intervals.
1722 */
[56789125]1723 leaf->value[i - 1] += count + right_cnt;
[da1bafb]1724 btree_remove(&area->used_space, right_pg, leaf);
[fc47885]1725 goto success;
[0b37882]1726 } else if (page == left_pg + (left_cnt << PAGE_WIDTH)) {
[6f4495f5]1727 /*
1728 * The interval can be added by simply growing
1729 * the left interval.
1730 */
[56789125]1731 leaf->value[i - 1] += count;
[fc47885]1732 goto success;
[0b37882]1733 } else if (page + (count << PAGE_WIDTH) == right_pg) {
[25bf215]1734 /*
[da1bafb]1735 * The interval can be addded by simply moving
[6f4495f5]1736 * base of the right interval down and
1737 * increasing its size accordingly.
[da1bafb]1738 */
[56789125]1739 leaf->value[i] += count;
[25bf215]1740 leaf->key[i] = page;
[fc47885]1741 goto success;
[25bf215]1742 } else {
1743 /*
[6f4495f5]1744 * The interval is between both neigbouring
1745 * intervals, but cannot be merged with any of
1746 * them.
[25bf215]1747 */
[da1bafb]1748 btree_insert(&area->used_space, page,
[6f4495f5]1749 (void *) count, leaf);
[fc47885]1750 goto success;
[25bf215]1751 }
1752 }
1753 }
[da1bafb]1754
[7e752b2]1755 panic("Inconsistency detected while adding %zu pages of used "
1756 "space at %p.", count, (void *) page);
[fc47885]1757
1758success:
1759 area->resident += count;
1760 return true;
[25bf215]1761}
1762
1763/** Mark portion of address space area as unused.
1764 *
1765 * The address space area must be already locked.
1766 *
[da1bafb]1767 * @param area Address space area.
1768 * @param page First page to be marked.
1769 * @param count Number of page to be marked.
1770 *
[fc47885]1771 * @return False on failure or true on success.
[25bf215]1772 *
1773 */
[fc47885]1774bool used_space_remove(as_area_t *area, uintptr_t page, size_t count)
[25bf215]1775{
[1d432f9]1776 ASSERT(mutex_locked(&area->lock));
[25bf215]1777 ASSERT(page == ALIGN_DOWN(page, PAGE_SIZE));
1778 ASSERT(count);
[da1bafb]1779
1780 btree_node_t *leaf;
1781 size_t pages = (size_t) btree_search(&area->used_space, page, &leaf);
[25bf215]1782 if (pages) {
1783 /*
1784 * We are lucky, page is the beginning of some interval.
1785 */
1786 if (count > pages) {
[fc47885]1787 return false;
[25bf215]1788 } else if (count == pages) {
[da1bafb]1789 btree_remove(&area->used_space, page, leaf);
[fc47885]1790 goto success;
[25bf215]1791 } else {
1792 /*
1793 * Find the respective interval.
1794 * Decrease its size and relocate its start address.
1795 */
[da1bafb]1796 btree_key_t i;
[25bf215]1797 for (i = 0; i < leaf->keys; i++) {
1798 if (leaf->key[i] == page) {
[0b37882]1799 leaf->key[i] += count << PAGE_WIDTH;
[56789125]1800 leaf->value[i] -= count;
[fc47885]1801 goto success;
[25bf215]1802 }
1803 }
[fc47885]1804
[25bf215]1805 goto error;
1806 }
1807 }
[da1bafb]1808
1809 btree_node_t *node = btree_leaf_node_left_neighbour(&area->used_space, leaf);
1810 if ((node) && (page < leaf->key[0])) {
[7f1c620]1811 uintptr_t left_pg = node->key[node->keys - 1];
[98000fb]1812 size_t left_cnt = (size_t) node->value[node->keys - 1];
[da1bafb]1813
[0b37882]1814 if (overlaps(left_pg, left_cnt << PAGE_WIDTH, page,
1815 count << PAGE_WIDTH)) {
1816 if (page + (count << PAGE_WIDTH) ==
1817 left_pg + (left_cnt << PAGE_WIDTH)) {
[25bf215]1818 /*
[6f4495f5]1819 * The interval is contained in the rightmost
1820 * interval of the left neighbour and can be
1821 * removed by updating the size of the bigger
1822 * interval.
[25bf215]1823 */
[56789125]1824 node->value[node->keys - 1] -= count;
[fc47885]1825 goto success;
[0b37882]1826 } else if (page + (count << PAGE_WIDTH) <
1827 left_pg + (left_cnt << PAGE_WIDTH)) {
[25bf215]1828 /*
[6f4495f5]1829 * The interval is contained in the rightmost
1830 * interval of the left neighbour but its
1831 * removal requires both updating the size of
1832 * the original interval and also inserting a
1833 * new interval.
[25bf215]1834 */
[0b37882]1835 size_t new_cnt = ((left_pg + (left_cnt << PAGE_WIDTH)) -
1836 (page + (count << PAGE_WIDTH))) >> PAGE_WIDTH;
[56789125]1837 node->value[node->keys - 1] -= count + new_cnt;
[da1bafb]1838 btree_insert(&area->used_space, page +
[0b37882]1839 (count << PAGE_WIDTH), (void *) new_cnt, leaf);
[fc47885]1840 goto success;
[25bf215]1841 }
1842 }
[fc47885]1843
1844 return false;
[da1bafb]1845 } else if (page < leaf->key[0])
[fc47885]1846 return false;
[25bf215]1847
1848 if (page > leaf->key[leaf->keys - 1]) {
[7f1c620]1849 uintptr_t left_pg = leaf->key[leaf->keys - 1];
[98000fb]1850 size_t left_cnt = (size_t) leaf->value[leaf->keys - 1];
[da1bafb]1851
[0b37882]1852 if (overlaps(left_pg, left_cnt << PAGE_WIDTH, page,
1853 count << PAGE_WIDTH)) {
1854 if (page + (count << PAGE_WIDTH) ==
1855 left_pg + (left_cnt << PAGE_WIDTH)) {
[25bf215]1856 /*
[6f4495f5]1857 * The interval is contained in the rightmost
1858 * interval of the leaf and can be removed by
1859 * updating the size of the bigger interval.
[25bf215]1860 */
[56789125]1861 leaf->value[leaf->keys - 1] -= count;
[fc47885]1862 goto success;
[0b37882]1863 } else if (page + (count << PAGE_WIDTH) < left_pg +
1864 (left_cnt << PAGE_WIDTH)) {
[25bf215]1865 /*
[6f4495f5]1866 * The interval is contained in the rightmost
1867 * interval of the leaf but its removal
1868 * requires both updating the size of the
1869 * original interval and also inserting a new
1870 * interval.
[25bf215]1871 */
[0b37882]1872 size_t new_cnt = ((left_pg + (left_cnt << PAGE_WIDTH)) -
1873 (page + (count << PAGE_WIDTH))) >> PAGE_WIDTH;
[56789125]1874 leaf->value[leaf->keys - 1] -= count + new_cnt;
[da1bafb]1875 btree_insert(&area->used_space, page +
[0b37882]1876 (count << PAGE_WIDTH), (void *) new_cnt, leaf);
[fc47885]1877 goto success;
[25bf215]1878 }
1879 }
[fc47885]1880
1881 return false;
[da1bafb]1882 }
[25bf215]1883
1884 /*
1885 * The border cases have been already resolved.
[fc47885]1886 * Now the interval can be only between intervals of the leaf.
[25bf215]1887 */
[da1bafb]1888 btree_key_t i;
[25bf215]1889 for (i = 1; i < leaf->keys - 1; i++) {
1890 if (page < leaf->key[i]) {
[7f1c620]1891 uintptr_t left_pg = leaf->key[i - 1];
[98000fb]1892 size_t left_cnt = (size_t) leaf->value[i - 1];
[da1bafb]1893
[25bf215]1894 /*
[6f4495f5]1895 * Now the interval is between intervals corresponding
1896 * to (i - 1) and i.
[25bf215]1897 */
[0b37882]1898 if (overlaps(left_pg, left_cnt << PAGE_WIDTH, page,
1899 count << PAGE_WIDTH)) {
1900 if (page + (count << PAGE_WIDTH) ==
1901 left_pg + (left_cnt << PAGE_WIDTH)) {
[25bf215]1902 /*
[6f4495f5]1903 * The interval is contained in the
1904 * interval (i - 1) of the leaf and can
1905 * be removed by updating the size of
1906 * the bigger interval.
[25bf215]1907 */
[56789125]1908 leaf->value[i - 1] -= count;
[fc47885]1909 goto success;
[0b37882]1910 } else if (page + (count << PAGE_WIDTH) <
1911 left_pg + (left_cnt << PAGE_WIDTH)) {
[25bf215]1912 /*
[6f4495f5]1913 * The interval is contained in the
1914 * interval (i - 1) of the leaf but its
1915 * removal requires both updating the
1916 * size of the original interval and
[25bf215]1917 * also inserting a new interval.
1918 */
[da1bafb]1919 size_t new_cnt = ((left_pg +
[0b37882]1920 (left_cnt << PAGE_WIDTH)) -
1921 (page + (count << PAGE_WIDTH))) >>
[6f4495f5]1922 PAGE_WIDTH;
[56789125]1923 leaf->value[i - 1] -= count + new_cnt;
[da1bafb]1924 btree_insert(&area->used_space, page +
[0b37882]1925 (count << PAGE_WIDTH), (void *) new_cnt,
[6f4495f5]1926 leaf);
[fc47885]1927 goto success;
[25bf215]1928 }
1929 }
[fc47885]1930
1931 return false;
[25bf215]1932 }
1933 }
[da1bafb]1934
[25bf215]1935error:
[7e752b2]1936 panic("Inconsistency detected while removing %zu pages of used "
1937 "space from %p.", count, (void *) page);
[fc47885]1938
1939success:
1940 area->resident -= count;
1941 return true;
[25bf215]1942}
1943
[df0103f7]1944/*
1945 * Address space related syscalls.
1946 */
1947
1948/** Wrapper for as_area_create(). */
[96b02eb9]1949sysarg_t sys_as_area_create(uintptr_t address, size_t size, unsigned int flags)
[df0103f7]1950{
[6f4495f5]1951 if (as_area_create(AS, flags | AS_AREA_CACHEABLE, size, address,
1952 AS_AREA_ATTR_NONE, &anon_backend, NULL))
[96b02eb9]1953 return (sysarg_t) address;
[df0103f7]1954 else
[96b02eb9]1955 return (sysarg_t) -1;
[df0103f7]1956}
1957
[c6e314a]1958/** Wrapper for as_area_resize(). */
[96b02eb9]1959sysarg_t sys_as_area_resize(uintptr_t address, size_t size, unsigned int flags)
[df0103f7]1960{
[96b02eb9]1961 return (sysarg_t) as_area_resize(AS, address, size, 0);
[7242a78e]1962}
1963
[c98e6ee]1964/** Wrapper for as_area_change_flags(). */
[96b02eb9]1965sysarg_t sys_as_area_change_flags(uintptr_t address, unsigned int flags)
[c98e6ee]1966{
[96b02eb9]1967 return (sysarg_t) as_area_change_flags(AS, flags, address);
[c98e6ee]1968}
1969
[c6e314a]1970/** Wrapper for as_area_destroy(). */
[96b02eb9]1971sysarg_t sys_as_area_destroy(uintptr_t address)
[7242a78e]1972{
[96b02eb9]1973 return (sysarg_t) as_area_destroy(AS, address);
[df0103f7]1974}
[b45c443]1975
[0b37882]1976/** Return pointer to unmapped address space area
1977 *
1978 * @param base Lowest address bound.
1979 * @param size Requested size of the allocation.
1980 *
1981 * @return Pointer to the beginning of unmapped address space area.
1982 *
1983 */
1984sysarg_t sys_as_get_unmapped_area(uintptr_t base, size_t size)
1985{
1986 if (size == 0)
1987 return 0;
1988
1989 /*
1990 * Make sure we allocate from page-aligned
1991 * address. Check for possible overflow in
1992 * each step.
1993 */
1994
1995 size_t pages = SIZE2FRAMES(size);
1996 uintptr_t ret = 0;
1997
1998 /*
1999 * Find the lowest unmapped address aligned on the sz
2000 * boundary, not smaller than base and of the required size.
2001 */
2002
2003 mutex_lock(&AS->lock);
2004
2005 /* First check the base address itself */
2006 uintptr_t addr = ALIGN_UP(base, PAGE_SIZE);
2007 if ((addr >= base) &&
2008 (check_area_conflicts(AS, addr, pages, NULL)))
2009 ret = addr;
2010
2011 /* Eventually check the addresses behind each area */
2012 link_t *cur;
2013 for (cur = AS->as_area_btree.leaf_head.next;
2014 (ret == 0) && (cur != &AS->as_area_btree.leaf_head);
2015 cur = cur->next) {
2016 btree_node_t *node =
2017 list_get_instance(cur, btree_node_t, leaf_link);
2018
2019 btree_key_t i;
2020 for (i = 0; (ret == 0) && (i < node->keys); i++) {
2021 as_area_t *area = (as_area_t *) node->value[i];
2022
2023 mutex_lock(&area->lock);
2024
2025 uintptr_t addr =
2026 ALIGN_UP(area->base + (area->pages << PAGE_WIDTH),
2027 PAGE_SIZE);
2028
2029 if ((addr >= base) && (addr >= area->base) &&
2030 (check_area_conflicts(AS, addr, pages, area)))
2031 ret = addr;
2032
2033 mutex_unlock(&area->lock);
2034 }
2035 }
2036
2037 mutex_unlock(&AS->lock);
2038
2039 return (sysarg_t) ret;
2040}
2041
[336db295]2042/** Get list of adress space areas.
2043 *
[da1bafb]2044 * @param as Address space.
2045 * @param obuf Place to save pointer to returned buffer.
2046 * @param osize Place to save size of returned buffer.
2047 *
[336db295]2048 */
2049void as_get_area_info(as_t *as, as_area_info_t **obuf, size_t *osize)
2050{
2051 mutex_lock(&as->lock);
[da1bafb]2052
[336db295]2053 /* First pass, count number of areas. */
[da1bafb]2054
2055 size_t area_cnt = 0;
2056 link_t *cur;
2057
[336db295]2058 for (cur = as->as_area_btree.leaf_head.next;
2059 cur != &as->as_area_btree.leaf_head; cur = cur->next) {
[da1bafb]2060 btree_node_t *node =
2061 list_get_instance(cur, btree_node_t, leaf_link);
[336db295]2062 area_cnt += node->keys;
2063 }
[da1bafb]2064
2065 size_t isize = area_cnt * sizeof(as_area_info_t);
2066 as_area_info_t *info = malloc(isize, 0);
2067
[336db295]2068 /* Second pass, record data. */
[da1bafb]2069
2070 size_t area_idx = 0;
2071
[336db295]2072 for (cur = as->as_area_btree.leaf_head.next;
2073 cur != &as->as_area_btree.leaf_head; cur = cur->next) {
[da1bafb]2074 btree_node_t *node =
2075 list_get_instance(cur, btree_node_t, leaf_link);
2076 btree_key_t i;
2077
[336db295]2078 for (i = 0; i < node->keys; i++) {
2079 as_area_t *area = node->value[i];
[da1bafb]2080
[336db295]2081 ASSERT(area_idx < area_cnt);
2082 mutex_lock(&area->lock);
[da1bafb]2083
[336db295]2084 info[area_idx].start_addr = area->base;
2085 info[area_idx].size = FRAMES2SIZE(area->pages);
2086 info[area_idx].flags = area->flags;
2087 ++area_idx;
[da1bafb]2088
[336db295]2089 mutex_unlock(&area->lock);
2090 }
2091 }
[da1bafb]2092
[336db295]2093 mutex_unlock(&as->lock);
[da1bafb]2094
[336db295]2095 *obuf = info;
2096 *osize = isize;
2097}
2098
[64c2ad5]2099/** Print out information about address space.
2100 *
[da1bafb]2101 * @param as Address space.
2102 *
[64c2ad5]2103 */
2104void as_print(as_t *as)
2105{
2106 mutex_lock(&as->lock);
2107
[0b37882]2108 /* Print out info about address space areas */
[64c2ad5]2109 link_t *cur;
[6f4495f5]2110 for (cur = as->as_area_btree.leaf_head.next;
2111 cur != &as->as_area_btree.leaf_head; cur = cur->next) {
[da1bafb]2112 btree_node_t *node
2113 = list_get_instance(cur, btree_node_t, leaf_link);
2114 btree_key_t i;
[64c2ad5]2115
2116 for (i = 0; i < node->keys; i++) {
[7ba7c6d]2117 as_area_t *area = node->value[i];
[da1bafb]2118
[64c2ad5]2119 mutex_lock(&area->lock);
[7e752b2]2120 printf("as_area: %p, base=%p, pages=%zu"
2121 " (%p - %p)\n", area, (void *) area->base,
2122 area->pages, (void *) area->base,
2123 (void *) (area->base + FRAMES2SIZE(area->pages)));
[64c2ad5]2124 mutex_unlock(&area->lock);
2125 }
2126 }
2127
2128 mutex_unlock(&as->lock);
2129}
2130
[cc73a8a1]2131/** @}
[b45c443]2132 */
Note: See TracBrowser for help on using the repository browser.