L4Re/departure

libexec/lib/src/external_pager.cc

574:b2aa14224c26
11 months ago Paul Boddie Ignored unused parameters.
     1 /*     2  * A system pager implementation residing in a separate task.     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/sys/task.h>    24 #include <l4/util/util.h>    25     26 #include <ipc/cap_alloc.h>    27 #include <ipc/map.h>    28 #include <ipc/mem_ipc.h>    29 #include <mem/memory_utils.h>    30 #include <systypes/base.h>    31     32 #include <stdio.h>    33     34 #include "external_pager.h"    35 #include "parent_pager_object_server.h"    36     37     38     39 #define DEBUG 0    40     41     42     43 /* A simple system pager also acting as a region mapper. */    44     45 ExternalPager::ExternalPager(address_t start, address_t end)    46 : ExecPager(start, end)    47 {    48 }    49     50 ipc_server_default_config_type ExternalPager::config()    51 {    52   return config_ParentPagerObject;    53 }    54     55     56     57 /* Close the pager. */    58     59 void ExternalPager::close()    60 {    61   printf("External pager closing...\n");    62     63   /* Remove pager regions to avoid unmapping them twice. */    64     65   remove(_rm_stack->region());    66     67   for (unsigned int i = 0; i < _rm_payload->segments(); i++)    68     remove(_rm_payload->segment(i)->region());    69     70   /* Delete the pager resources. */    71     72   if (_rm_payload != NULL)    73     delete _rm_payload;    74     75   if (_rm_stack != NULL)    76     delete _rm_stack;    77     78   /* Unmap all remaining regions. */    79     80   AvailableMemoryArea::iterator it;    81     82   for (it = _area.begin(); it != _area.end(); it++)    83   {    84     MemoryArea *r = *it;    85     86     if (r->is_mapped())    87       ipc_detach_dataspace((void *) r->dataspace_start());    88   }    89     90   /* Free all capabilities. */    91     92   Capabilities::iterator itc;    93     94   for (itc = _dataspaces.begin(); itc != _dataspaces.end(); itc++)    95     ipc_cap_free_um(*itc);    96     97   /* Notify the monitor. */    98     99   if (_monitor != NULL)   100     _monitor->pager_ended();   101 }   102    103    104    105 /* Capability management. */   106    107 void ExternalPager::set_pager(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap)   108 {   109   _pager = cap;   110   _mapped_pager = mapped_cap;   111 }   112    113 void ExternalPager::set_parent(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap)   114 {   115   _parent = cap;   116   _mapped_parent = mapped_cap;   117 }   118    119 void ExternalPager::set_task(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap)   120 {   121   _task = cap;   122   _mapped_task = mapped_cap;   123 }   124    125 void ExternalPager::set_thread(l4_cap_idx_t cap, l4_cap_idx_t mapped_cap)   126 {   127   _thread = cap;   128   _mapped_thread = mapped_cap;   129 }   130    131    132    133 /* Lifecycle management. */   134    135 void ExternalPager::set_monitor(ProcessMonitor *monitor)   136 {   137   _monitor = monitor;   138 }   139    140    141    142 /* Manage pager resources. */   143    144 void ExternalPager::set_payload(Payload *payload)   145 {   146   _rm_payload = payload;   147 }   148    149 void ExternalPager::set_stack(ExplicitSegment *stack)   150 {   151   _rm_stack = stack;   152 }   153    154    155    156 /* Handle a general exception. */   157    158 long ExternalPager::exception(l4_exc_regs_t regs, l4_snd_fpage_t *region)   159 {   160   (void) region;   161    162   printf("ExternalPager::exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(&regs), l4_utcb_exc_pc(&regs));   163    164   while (1)   165     l4_sleep_forever();   166    167   return L4_EOK;   168 }   169    170 /* Handle a page fault using any configured regions. */   171    172 long ExternalPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region)   173 {   174   l4_umword_t addr = pfa & ~7UL, flags = pfa & 7;   175    176 #if DEBUG   177   printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags);   178 #endif   179    180   /* Obtain a region supporting the fault address. */   181    182   MemoryArea *r, *parent;   183   long err = _area.find(addr, &r, &parent);   184    185   if (!err)   186   {   187     l4_addr_t page_addr = trunc(addr, L4_PAGESIZE);   188     map_flags_t map_flags = map_flags_for_fault(flags);   189    190     region->fpage = l4_fpage(r->dataspace_start() + (page_addr - r->area_start()), L4_PAGESHIFT, map_flags & r->flags());   191     region->snd_base = page_addr;   192    193 #if DEBUG   194     printf("%lx...%lx from %lx...%lx offset %lx size %d rights %x ds %lx\n",   195            r->area_start(), region->snd_base,   196            r->dataspace_start(), l4_fpage_memaddr(region->fpage),   197            addr - r->area_start(),   198            l4_fpage_size(region->fpage),   199            l4_fpage_rights(region->fpage),   200            r->dataspace());   201    202     printf("%lx -> ", addr);   203    204     for (unsigned int i = 0; i < sizeof(l4_umword_t); i++)   205       printf("%02x", *((unsigned char *)(r->dataspace_start() + (addr - r->area_start()) + i)));   206    207     printf("\n");   208 #endif   209    210     if (r->flags() & L4RE_RM_F_W)   211       l4_touch_rw((const void *) (r->dataspace_start() + (page_addr - r->area_start())), L4_PAGESIZE);   212     else   213       l4_touch_ro((const void *) (r->dataspace_start() + (page_addr - r->area_start())), L4_PAGESIZE);   214    215     return L4_EOK;   216   }   217    218   printf("not mapped at %lx for pc %lx\n", addr, pc);   219    220   return err;   221 }   222    223 /* Attach a region for provision when page faults occur. This is required in   224    the initialisation of a program by the C library which requires a region   225    mapper. */   226    227 long ExternalPager::attach(address_t *start, address_t size, map_flags_t flags,   228                            l4_cap_idx_t ds, address_t offset,   229                            unsigned char align)   230 {   231   // NOTE: Determine the purpose of offset.   232    233   (void) offset;   234    235   MemoryArea *area;   236   long err = ExecPager::find(start, &size, flags, align, &area);   237    238   /* Without an error, attach the dataspace. */   239    240   if (!err)   241   {   242     /* Attach the provided dataspace within this task.   243    244        This is only done in this implementation to support the paging   245        mechanism. In a region mapper residing within the actual task, the   246        dataspace's map operation would be invoked to obtain mappings. */   247    248     l4_addr_t ds_start;   249     err = ipc_attach_dataspace(ds, size, (void **) &ds_start);   250    251     if (err)   252       return err;   253    254     l4_touch_rw((const void *) ds_start, size);   255    256     MappedRegion r(*start, *start + size, flags & L4RE_DS_F_RIGHTS_MASK, ds, ds_start);   257     area->add(r);   258    259     /* Record dataspaces separately. */   260    261     _dataspaces.insert(ds);   262   }   263    264   /* Discard the imported dataspace if its region cannot be accommodated. */   265    266   else   267     ipc_cap_free_um(ds);   268    269   return err;   270 }   271    272    273    274 /* Receive signals from a task. */   275    276 long ExternalPager::signal(unsigned long sig, unsigned long val)   277 {   278   (void) val;   279    280   /* Handle the termination event of the internal pager. */   281    282   if (sig == 0)   283   {   284     printf("Signal from internal pager.\n");   285    286     /* For some reason, threads cannot be released by the process, so they are   287        also unmapped on its behalf. */   288    289     if (l4_is_valid_cap(_thread))   290     {   291       ipc_cap_free_um(_thread);   292       ipc_unmap_capability(_task, _mapped_thread);   293       _thread = L4_INVALID_CAP;   294    295       /* Parent and pager/region mapper. Freeing the pager after the thread   296          should avoid warnings about invalid pager capabilities. */   297    298       ipc_unmap_capability(_task, _mapped_parent);   299       ipc_unmap_capability(_task, _mapped_pager);   300     }   301   }   302    303   return L4_EOK;   304 }   305    306 /* vim: tabstop=2 expandtab shiftwidth=2   307 */