L4Re/departure

libexec/lib/src/internal_pager.cc

515:bae2ddb47ecd
20 months ago Paul Boddie Introduced support for reserve_area in the internal pager along with different kinds of memory area. This permits the execution of threaded programs.
     1 /*     2  * A system pager implementation residing in the same task as a program.     3  *     4  * Copyright (C) 2022, 2023 Paul Boddie <paul@boddie.org.uk>     5  *     6  * This program is free software; you can redistribute it and/or     7  * modify it under the terms of the GNU General Public License as     8  * published by the Free Software Foundation; either version 2 of     9  * the License, or (at your option) any later version.    10  *    11  * This program is distributed in the hope that it will be useful,    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    14  * GNU General Public License for more details.    15  *    16  * You should have received a copy of the GNU General Public License    17  * along with this program; if not, write to the Free Software    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,    19  * Boston, MA  02110-1301, USA    20  */    21     22 #include <l4/re/env.h>    23 #include <l4/re/c/dataspace.h>    24 #include <l4/re/c/rm.h>    25 #include <l4/util/util.h>    26     27 #include <ipc/cap_alloc.h>    28 #include <mem/memory_utils.h>    29 #include <systypes/base.h>    30     31 #include <stdio.h>    32     33 #include "dataspace_client.h"    34 #include "internal_pager.h"    35 #include "mapped_region.h"    36 #include "pager_object_server.h"    37     38     39     40 #define DEBUG 0    41     42     43     44 /* A simple system pager also acting as a region mapper. */    45     46 InternalPager::InternalPager(address_t start, address_t end)    47 : ExecPager(start, end)    48 {    49 }    50     51 ipc_server_default_config_type InternalPager::config()    52 {    53   return config_PagerObject;    54 }    55     56     57     58 /* Close the pager. */    59     60 void InternalPager::close()    61 {    62   printf("Internal pager closing...\n");    63     64   /* Unmap all regions. */    65     66   Capabilities::iterator itc;    67     68   for (itc = _dataspaces.begin(); itc != _dataspaces.end(); itc++)    69     ipc_cap_free_um(*itc);    70 }    71     72     73     74 /* Handle a general exception. */    75     76 long InternalPager::exception(l4_exc_regs_t regs, l4_snd_fpage_t *region)    77 {    78   (void) region;    79     80   printf("InternalPager::exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(&regs), l4_utcb_exc_pc(&regs));    81     82 #if DEBUG    83   while (1)    84     l4_sleep_forever();    85 #endif    86     87   return L4_EOK;    88 }    89     90 /* Handle a page fault using any configured regions. */    91     92 long InternalPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region)    93 {    94   l4_umword_t addr = pfa & ~7UL, flags = pfa & 7;    95     96 #if DEBUG    97   printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags);    98   l4_thread_regs_t *regs = l4_utcb_tcr();    99   printf("regs = %p\n; regs->user[0] = %lx\n", regs, regs->user[0]);   100 #endif   101    102   /* Obtain a region supporting the fault address. */   103    104   MemoryArea *r;   105   long err = _area.find(addr, &r);   106    107   if (!err)   108   {   109     address_t window_size = L4_PAGESIZE;   110     address_t window_base = trunc(addr, window_size);   111     address_t offset = addr - r->area_start();   112     address_t page_addr = trunc(addr, L4_PAGESIZE);   113     address_t hot_spot = page_addr - window_base;   114    115     /* Interact with the region's dataspace, specifying a receive window for a   116        map operation. Here, a single page is specified. */   117    118     client_Dataspace dataspace(r->dataspace());   119     l4_snd_fpage_t rw_region = {0, l4_fpage(window_base, L4_PAGESHIFT, 0)};   120     map_flags_t map_flags = map_flags_for_fault(flags);   121    122 #if DEBUG   123     printf("window_base = %lx; window_size = %lx\n", window_base, window_size);   124     printf("region = {%lx, {%lx, %d}}\n", rw_region.snd_base, l4_fpage_memaddr(rw_region.fpage), l4_fpage_size(rw_region.fpage));   125     printf("map(%lx, %lx, %lx) -> %lx\n", offset, hot_spot, map_flags, r->dataspace());   126 #endif   127    128     err = dataspace.map(offset, hot_spot, map_flags & r->flags(), &rw_region);   129    130     /* Indicate an unspecified result, since the mapping should have taken   131        place. */   132    133     *region = {0, l4_fpage_invalid()};   134    135     return err;   136   }   137    138   printf("not mapped at %lx for pc %lx\n", addr, pc);   139    140   return err;   141 }   142    143 /* Attach a region for provision when page faults occur. This is required in   144    the initialisation of a program by the C library which requires a region   145    mapper. */   146    147 long InternalPager::attach(address_t *start, address_t size, map_flags_t flags,   148                            l4_cap_idx_t ds, address_t offset,   149                            unsigned char align)   150 {   151   // NOTE: Determine the purpose of offset.   152    153   (void) offset;   154    155   MemoryArea *area;   156   long err = ExecPager::find(start, &size, flags, align, &area);   157    158   if (!err)   159   {   160     MappedRegion r(*start, *start + size, flags & L4RE_DS_F_RIGHTS_MASK, ds);   161     area->add(r);   162    163     /* Record dataspaces separately. */   164    165     _dataspaces.insert(ds);   166   }   167   else   168     ipc_cap_free_um(ds);   169    170   return err;   171 }   172    173 long InternalPager::reserve_area(address_t *start, address_t size,   174                                  map_flags_t flags, unsigned char align)   175 {   176   MemoryArea *area;   177   long err = ExecPager::find(start, &size, flags, align, &area);   178    179   if (!err)   180   {   181     /* Add an object acting like a region but without any associated   182        dataspace. */   183    184     if (flags & L4RE_RM_F_RESERVED)   185     {   186       ReservedMemoryArea r(*start, *start + size);   187       area->add(r);   188     }   189    190     /* Add an object permitting regions to be added within it. */   191    192     else   193     {   194       AvailableMemoryArea r(*start, *start + size);   195       area->add(r);   196     }   197   }   198    199   return err;   200 }   201    202 /* vim: tabstop=2 expandtab shiftwidth=2   203 */