1.1 --- a/libexec/include/exec/internal_pager.h Tue Mar 14 23:51:57 2023 +0100
1.2 +++ b/libexec/include/exec/internal_pager.h Wed Mar 15 00:33:40 2023 +0100
1.3 @@ -58,6 +58,9 @@
1.4
1.5 virtual long attach(address_t *start, address_t size, map_flags_t flags,
1.6 l4_cap_idx_t ds, address_t offset, unsigned char align);
1.7 +
1.8 + virtual long reserve_area(address_t *start, address_t size, map_flags_t flags,
1.9 + unsigned char align);
1.10 };
1.11
1.12 /* vim: tabstop=2 expandtab shiftwidth=2
2.1 --- a/libexec/include/exec/mapped_region.h Tue Mar 14 23:51:57 2023 +0100
2.2 +++ b/libexec/include/exec/mapped_region.h Wed Mar 15 00:33:40 2023 +0100
2.3 @@ -1,7 +1,7 @@
2.4 /*
2.5 * Mapped memory region support.
2.6 *
2.7 - * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
2.8 + * Copyright (C) 2022, 2023 Paul Boddie <paul@boddie.org.uk>
2.9 *
2.10 * This program is free software; you can redistribute it and/or
2.11 * modify it under the terms of the GNU General Public License as
2.12 @@ -23,32 +23,51 @@
2.13
2.14 #include <l4/sys/types.h>
2.15
2.16 +#include <exec/memory_area.h>
2.17 #include <systypes/base.h>
2.18
2.19
2.20
2.21 /* A mapped region abstraction. */
2.22
2.23 -class MappedRegion
2.24 +class MappedRegion : public MemoryArea
2.25 {
2.26 +protected:
2.27 + l4_umword_t _flags;
2.28 + l4_cap_idx_t _ds;
2.29 + address_t _ds_start;
2.30 +
2.31 public:
2.32 - l4_addr_t start;
2.33 - offset_t size;
2.34 - l4_umword_t flags;
2.35 - l4_cap_idx_t ds;
2.36 - l4_addr_t ds_start;
2.37 -
2.38 explicit MappedRegion()
2.39 - : start(0), size(0), flags(0), ds(L4_INVALID_CAP), ds_start(0)
2.40 + : MemoryArea(), _flags(0), _ds(L4_INVALID_CAP), _ds_start(0)
2.41 {
2.42 }
2.43
2.44 - explicit MappedRegion(l4_addr_t start, l4_addr_t size,
2.45 + explicit MappedRegion(address_t start, address_t end,
2.46 l4_umword_t flags, l4_cap_idx_t ds = L4_INVALID_CAP,
2.47 - l4_addr_t ds_start = 0)
2.48 - : start(start), size(size), flags(flags), ds(ds), ds_start(ds_start)
2.49 + address_t ds_start = 0)
2.50 + : MemoryArea(start, end), _flags(flags), _ds(ds), _ds_start(ds_start)
2.51 {
2.52 }
2.53 +
2.54 + virtual MemoryArea *copy()
2.55 + { return new MappedRegion(_start, _end, _flags, _ds, _ds_start); }
2.56 +
2.57 + /* Access to area properties. */
2.58 +
2.59 + virtual l4_umword_t flags()
2.60 + { return _flags; }
2.61 +
2.62 + virtual l4_cap_idx_t dataspace()
2.63 + { return _ds; }
2.64 +
2.65 + virtual address_t dataspace_start()
2.66 + { return _ds_start; }
2.67 +
2.68 + /* Return whether the area provides a mapped region. */
2.69 +
2.70 + virtual bool is_mapped()
2.71 + { return true; }
2.72 };
2.73
2.74 /* vim: tabstop=2 expandtab shiftwidth=2
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/libexec/include/exec/memory_area.h Wed Mar 15 00:33:40 2023 +0100
3.3 @@ -0,0 +1,218 @@
3.4 +/*
3.5 + * Memory area support.
3.6 + *
3.7 + * Copyright (C) 2022, 2023 Paul Boddie <paul@boddie.org.uk>
3.8 + *
3.9 + * This program is free software; you can redistribute it and/or
3.10 + * modify it under the terms of the GNU General Public License as
3.11 + * published by the Free Software Foundation; either version 2 of
3.12 + * the License, or (at your option) any later version.
3.13 + *
3.14 + * This program is distributed in the hope that it will be useful,
3.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.17 + * GNU General Public License for more details.
3.18 + *
3.19 + * You should have received a copy of the GNU General Public License
3.20 + * along with this program; if not, write to the Free Software
3.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
3.22 + * Boston, MA 02110-1301, USA
3.23 + */
3.24 +
3.25 +#pragma once
3.26 +
3.27 +#include <map>
3.28 +#include <set>
3.29 +#include <stack>
3.30 +
3.31 +#include <l4/sys/types.h>
3.32 +
3.33 +#include <systypes/base.h>
3.34 +
3.35 +
3.36 +
3.37 +/* A memory area abstraction. */
3.38 +
3.39 +class MemoryArea
3.40 +{
3.41 +protected:
3.42 + address_t _start, _end;
3.43 +
3.44 +public:
3.45 + explicit MemoryArea()
3.46 + : _start(0), _end(0)
3.47 + {
3.48 + }
3.49 +
3.50 + explicit MemoryArea(address_t start, address_t end)
3.51 + : _start(start), _end(end)
3.52 + {
3.53 + }
3.54 +
3.55 + virtual ~MemoryArea()
3.56 + {
3.57 + }
3.58 +
3.59 + virtual MemoryArea *copy();
3.60 +
3.61 + /* Access to area properties. */
3.62 +
3.63 + virtual address_t area_start()
3.64 + { return _start; }
3.65 +
3.66 + virtual address_t area_end()
3.67 + { return _end; }
3.68 +
3.69 + virtual l4_umword_t flags()
3.70 + { return 0; }
3.71 +
3.72 + virtual l4_cap_idx_t dataspace()
3.73 + { return L4_INVALID_CAP; }
3.74 +
3.75 + virtual address_t dataspace_start()
3.76 + { return 0; }
3.77 +
3.78 + /* Return whether the area supports the given address. */
3.79 +
3.80 + virtual bool supports(address_t addr)
3.81 + { return (_start <= addr) && (addr < _end); }
3.82 +
3.83 + /* Return whether an area is reserved and therefore cannot be mapped. */
3.84 +
3.85 + virtual bool is_reserved()
3.86 + { return false; }
3.87 +
3.88 + /* Return whether the area provides a mapped region. */
3.89 +
3.90 + virtual bool is_mapped()
3.91 + { return false; }
3.92 +
3.93 + /* Support for populating areas. */
3.94 +
3.95 + virtual long add(MemoryArea &area);
3.96 +
3.97 + virtual long remove(MemoryArea &area);
3.98 +
3.99 + /* Support for finding regions. */
3.100 +
3.101 + virtual long find(address_t addr, MemoryArea **area);
3.102 +
3.103 + /* Support for finding areas. */
3.104 +
3.105 + virtual long find(address_t *start, address_t *size, map_flags_t flags,
3.106 + unsigned char align, MemoryArea **area);
3.107 +};
3.108 +
3.109 +
3.110 +
3.111 +/* A reserved area abstraction. */
3.112 +
3.113 +class ReservedMemoryArea : public MemoryArea
3.114 +{
3.115 +public:
3.116 + explicit ReservedMemoryArea(address_t start, address_t end)
3.117 + : MemoryArea(start, end)
3.118 + {
3.119 + }
3.120 +
3.121 + virtual MemoryArea *copy();
3.122 +
3.123 + /* Return whether an area is reserved and therefore cannot be mapped. */
3.124 +
3.125 + virtual bool is_reserved()
3.126 + { return true; }
3.127 +
3.128 + /* Support for finding areas. */
3.129 +
3.130 + virtual long find(address_t addr, MemoryArea **area);
3.131 +};
3.132 +
3.133 +
3.134 +
3.135 +/* Collection types. */
3.136 +
3.137 +typedef std::map<address_t, MemoryArea *> MemoryAreaMap;
3.138 +typedef std::set<MemoryArea *> MemoryAreas;
3.139 +
3.140 +
3.141 +
3.142 +/* A memory area containing other areas. */
3.143 +
3.144 +class AvailableMemoryArea : public MemoryArea
3.145 +{
3.146 +protected:
3.147 + MemoryAreaMap _areas;
3.148 + MemoryAreas _allocated;
3.149 +
3.150 +public:
3.151 + explicit AvailableMemoryArea(address_t start, address_t end)
3.152 + : MemoryArea(start, end)
3.153 + {
3.154 + }
3.155 +
3.156 + virtual ~AvailableMemoryArea();
3.157 +
3.158 + virtual MemoryArea *copy();
3.159 +
3.160 + /* Support for populating areas. */
3.161 +
3.162 + virtual long add(MemoryArea &area);
3.163 +
3.164 + virtual long remove(MemoryArea &area);
3.165 +
3.166 + /* Support for finding areas. */
3.167 +
3.168 + virtual long find(address_t addr, MemoryArea **area);
3.169 +
3.170 + virtual long find(address_t *start, address_t *size, map_flags_t flags,
3.171 + unsigned char align, MemoryArea **area);
3.172 +
3.173 + /* A recursive iterator over a memory area. */
3.174 +
3.175 + class iterator
3.176 + {
3.177 + protected:
3.178 + std::stack<MemoryAreaMap::iterator> _iterators, _ends;
3.179 +
3.180 + void ascend();
3.181 +
3.182 + void descend();
3.183 +
3.184 + void descend_all();
3.185 +
3.186 + public:
3.187 + explicit iterator();
3.188 +
3.189 + explicit iterator(MemoryAreaMap::iterator it,
3.190 + MemoryAreaMap::iterator end);
3.191 +
3.192 + MemoryArea *operator *();
3.193 +
3.194 + iterator &operator ++();
3.195 +
3.196 + iterator &operator ++(int);
3.197 +
3.198 + bool operator ==(iterator other);
3.199 +
3.200 + bool operator !=(iterator other);
3.201 +
3.202 + /* Access to the underlying iterators. */
3.203 +
3.204 + MemoryAreaMap::iterator &area_iterator();
3.205 +
3.206 + MemoryAreaMap::iterator &area_end();
3.207 + };
3.208 +
3.209 + /* Iteration methods. */
3.210 +
3.211 + virtual iterator begin();
3.212 +
3.213 + virtual iterator end();
3.214 +
3.215 + virtual MemoryAreaMap::iterator areas_begin();
3.216 +
3.217 + virtual MemoryAreaMap::iterator areas_end();
3.218 +};
3.219 +
3.220 +/* vim: tabstop=2 expandtab shiftwidth=2
3.221 +*/
4.1 --- a/libexec/include/exec/pager.h Tue Mar 14 23:51:57 2023 +0100
4.2 +++ b/libexec/include/exec/pager.h Wed Mar 15 00:33:40 2023 +0100
4.3 @@ -21,15 +21,15 @@
4.4
4.5 #pragma once
4.6
4.7 -#include <map>
4.8 +#include <set>
4.9
4.10 -#include <exec/mapped_region.h>
4.11 +#include <exec/memory_area.h>
4.12
4.13
4.14
4.15 -/* Collection types. */
4.16 +/* Collection definitions. */
4.17
4.18 -typedef std::map<l4_addr_t, MappedRegion> MappedRegions;
4.19 +typedef std::set<l4_cap_idx_t> Capabilities;
4.20
4.21
4.22
4.23 @@ -38,14 +38,19 @@
4.24 class ExecPager
4.25 {
4.26 protected:
4.27 - address_t _start, _end;
4.28 +
4.29 + /* Top-level area containing other areas and regions. */
4.30 +
4.31 + AvailableMemoryArea _area;
4.32 +
4.33 + /* Dataspace capabilities associated with regions. */
4.34 +
4.35 + Capabilities _dataspaces;
4.36
4.37 /* Region manager/mapper functionality. */
4.38
4.39 - MappedRegions _regions;
4.40 -
4.41 virtual long find(address_t *start, address_t *size, map_flags_t flags,
4.42 - address_t offset, unsigned char align);
4.43 + unsigned char align, MemoryArea **area);
4.44
4.45 public:
4.46 explicit ExecPager(address_t start = 0, address_t end = 0);
4.47 @@ -54,9 +59,9 @@
4.48
4.49 /* Region management methods. */
4.50
4.51 - virtual void add(MappedRegion ®ion);
4.52 + virtual void add(MemoryArea &area);
4.53
4.54 - virtual void remove(MappedRegion ®ion);
4.55 + virtual void remove(MemoryArea &area);
4.56
4.57 /* Notification methods. */
4.58
5.1 --- a/libexec/lib/src/Makefile Tue Mar 14 23:51:57 2023 +0100
5.2 +++ b/libexec/lib/src/Makefile Wed Mar 15 00:33:40 2023 +0100
5.3 @@ -28,8 +28,11 @@
5.4 # Normal source files.
5.5
5.6 PLAIN_SRC_CC = \
5.7 - common.cc elf.cc external_pager.cc \
5.8 - internal_pager.cc memory.cc pager.cc \
5.9 + common.cc elf.cc \
5.10 + external_pager.cc \
5.11 + internal_pager.cc \
5.12 + memory.cc memory_area.cc \
5.13 + pager.cc \
5.14 process.cc process_creating.cc \
5.15 process_creator_context_resource.cc \
5.16 process_creator_resource.cc \
6.1 --- a/libexec/lib/src/external_pager.cc Tue Mar 14 23:51:57 2023 +0100
6.2 +++ b/libexec/lib/src/external_pager.cc Wed Mar 15 00:33:40 2023 +0100
6.3 @@ -58,7 +58,7 @@
6.4
6.5 void ExternalPager::close()
6.6 {
6.7 - printf("Pager closing...\n");
6.8 + printf("External pager closing...\n");
6.9
6.10 /* Remove pager regions to avoid unmapping them twice. */
6.11
6.12 @@ -77,15 +77,22 @@
6.13
6.14 /* Unmap all remaining regions. */
6.15
6.16 - MappedRegions::iterator it;
6.17 + AvailableMemoryArea::iterator it;
6.18
6.19 - for (it = _regions.begin(); it != _regions.end(); it++)
6.20 + for (it = _area.begin(); it != _area.end(); it++)
6.21 {
6.22 - MappedRegion &r = it->second;
6.23 + MemoryArea *r = *it;
6.24 +
6.25 + if (r->is_mapped())
6.26 + ipc_detach_dataspace((void *) r->dataspace_start());
6.27 + }
6.28
6.29 - ipc_detach_dataspace((void *) r.ds_start);
6.30 - ipc_cap_free_um(r.ds);
6.31 - }
6.32 + /* Free all capabilities. */
6.33 +
6.34 + Capabilities::iterator itc;
6.35 +
6.36 + for (itc = _dataspaces.begin(); itc != _dataspaces.end(); itc++)
6.37 + ipc_cap_free_um(*itc);
6.38
6.39 /* Remove the created task. */
6.40
6.41 @@ -172,61 +179,47 @@
6.42 printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags);
6.43 #endif
6.44
6.45 - /* Find the first region whose start address is beyond the fault address,
6.46 - testing if any immediately preceding region contains the fault address. */
6.47 -
6.48 - MappedRegions::iterator it = _regions.upper_bound(addr);
6.49 + /* Obtain a region supporting the fault address. */
6.50
6.51 - if (it != _regions.begin())
6.52 - it--;
6.53 - else
6.54 - {
6.55 - printf("not mapped at %lx for pc %lx\n", addr, pc);
6.56 - return -L4_ENOMEM;
6.57 - }
6.58 + MemoryArea *r;
6.59 + long err = _area.find(addr, &r);
6.60
6.61 - /* Obtain the region and test if it contains the fault address. */
6.62 -
6.63 - MappedRegion &r = it->second;
6.64 -
6.65 - if ((addr >= r.start) && (addr < r.start + r.size))
6.66 + if (!err)
6.67 {
6.68 l4_addr_t page_addr = trunc(addr, L4_PAGESIZE);
6.69 map_flags_t map_flags = map_flags_for_fault(flags);
6.70
6.71 - region->fpage = l4_fpage(r.ds_start + (page_addr - r.start), L4_PAGESHIFT, map_flags & r.flags);
6.72 + region->fpage = l4_fpage(r->dataspace_start() + (page_addr - r->area_start()), L4_PAGESHIFT, map_flags & r->flags());
6.73 region->snd_base = page_addr;
6.74
6.75 #if DEBUG
6.76 printf("%lx...%lx from %lx...%lx offset %lx size %d rights %x ds %lx\n",
6.77 - r.start, region->snd_base,
6.78 - r.ds_start, l4_fpage_memaddr(region->fpage),
6.79 - addr - r.start,
6.80 + r->area_start(), region->snd_base,
6.81 + r->dataspace_start(), l4_fpage_memaddr(region->fpage),
6.82 + addr - r->area_start(),
6.83 l4_fpage_size(region->fpage),
6.84 l4_fpage_rights(region->fpage),
6.85 - r.ds);
6.86 + r->dataspace());
6.87
6.88 printf("%lx -> ", addr);
6.89
6.90 for (unsigned int i = 0; i < sizeof(l4_umword_t); i++)
6.91 - printf("%02x", *((unsigned char *)(r.ds_start + (addr - r.start) + i)));
6.92 + printf("%02x", *((unsigned char *)(r->dataspace_start() + (addr - r->area_start()) + i)));
6.93
6.94 printf("\n");
6.95 #endif
6.96
6.97 - if (r.flags & L4RE_RM_F_W)
6.98 - l4_touch_rw((const void *) (r.ds_start + (page_addr - r.start)), L4_PAGESIZE);
6.99 + if (r->flags() & L4RE_RM_F_W)
6.100 + l4_touch_rw((const void *) (r->dataspace_start() + (page_addr - r->area_start())), L4_PAGESIZE);
6.101 else
6.102 - l4_touch_ro((const void *) (r.ds_start + (page_addr - r.start)), L4_PAGESIZE);
6.103 + l4_touch_ro((const void *) (r->dataspace_start() + (page_addr - r->area_start())), L4_PAGESIZE);
6.104
6.105 return L4_EOK;
6.106 }
6.107
6.108 -#if DEBUG
6.109 - printf("not mapped!\n");
6.110 -#endif
6.111 + printf("not mapped at %lx for pc %lx\n", addr, pc);
6.112
6.113 - return -L4_ENOMEM;
6.114 + return err;
6.115 }
6.116
6.117 /* Attach a region for provision when page faults occur. This is required in
6.118 @@ -237,7 +230,12 @@
6.119 l4_cap_idx_t ds, address_t offset,
6.120 unsigned char align)
6.121 {
6.122 - long err = ExecPager::find(start, &size, flags, offset, align);
6.123 + // NOTE: Determine the purpose of offset.
6.124 +
6.125 + (void) offset;
6.126 +
6.127 + MemoryArea *area;
6.128 + long err = ExecPager::find(start, &size, flags, align, &area);
6.129
6.130 /* Without an error, attach the dataspace. */
6.131
6.132 @@ -257,8 +255,12 @@
6.133
6.134 l4_touch_rw((const void *) ds_start, size);
6.135
6.136 - MappedRegion r(*start, size, flags & L4RE_DS_F_RIGHTS_MASK, ds, ds_start);
6.137 - add(r);
6.138 + MappedRegion r(*start, *start + size, flags & L4RE_DS_F_RIGHTS_MASK, ds, ds_start);
6.139 + area->add(r);
6.140 +
6.141 + /* Record dataspaces separately. */
6.142 +
6.143 + _dataspaces.insert(ds);
6.144 }
6.145
6.146 /* Discard the imported dataspace if its region cannot be accommodated. */
6.147 @@ -281,6 +283,8 @@
6.148
6.149 if (sig == 0)
6.150 {
6.151 + printf("Signal from task.\n");
6.152 +
6.153 /* Once the program exits, the IPC gate connecting the program with its
6.154 internal pager can be released. */
6.155
7.1 --- a/libexec/lib/src/internal_pager.cc Tue Mar 14 23:51:57 2023 +0100
7.2 +++ b/libexec/lib/src/internal_pager.cc Wed Mar 15 00:33:40 2023 +0100
7.3 @@ -21,6 +21,7 @@
7.4
7.5 #include <l4/re/env.h>
7.6 #include <l4/re/c/dataspace.h>
7.7 +#include <l4/re/c/rm.h>
7.8 #include <l4/util/util.h>
7.9
7.10 #include <ipc/cap_alloc.h>
7.11 @@ -31,6 +32,7 @@
7.12
7.13 #include "dataspace_client.h"
7.14 #include "internal_pager.h"
7.15 +#include "mapped_region.h"
7.16 #include "pager_object_server.h"
7.17
7.18
7.19 @@ -61,14 +63,10 @@
7.20
7.21 /* Unmap all regions. */
7.22
7.23 - MappedRegions::iterator it;
7.24 + Capabilities::iterator itc;
7.25
7.26 - for (it = _regions.begin(); it != _regions.end(); it++)
7.27 - {
7.28 - MappedRegion &r = it->second;
7.29 -
7.30 - ipc_cap_free_um(r.ds);
7.31 - }
7.32 + for (itc = _dataspaces.begin(); itc != _dataspaces.end(); itc++)
7.33 + ipc_cap_free_um(*itc);
7.34 }
7.35
7.36
7.37 @@ -101,43 +99,33 @@
7.38 printf("regs = %p\n; regs->user[0] = %lx\n", regs, regs->user[0]);
7.39 #endif
7.40
7.41 - /* Find the first region whose start address is beyond the fault address,
7.42 - testing if any immediately preceding region contains the fault address. */
7.43 -
7.44 - MappedRegions::iterator it = _regions.upper_bound(addr);
7.45 + /* Obtain a region supporting the fault address. */
7.46
7.47 - if (it != _regions.begin())
7.48 - it--;
7.49 - else
7.50 - {
7.51 - printf("not mapped at %lx for pc %lx\n", addr, pc);
7.52 - return -L4_ENOMEM;
7.53 - }
7.54 + MemoryArea *r;
7.55 + long err = _area.find(addr, &r);
7.56
7.57 - MappedRegion &r = it->second;
7.58 -
7.59 - if ((addr >= r.start) && (addr < r.start + r.size))
7.60 + if (!err)
7.61 {
7.62 address_t window_size = L4_PAGESIZE;
7.63 address_t window_base = trunc(addr, window_size);
7.64 - address_t offset = addr - r.start;
7.65 + address_t offset = addr - r->area_start();
7.66 address_t page_addr = trunc(addr, L4_PAGESIZE);
7.67 address_t hot_spot = page_addr - window_base;
7.68
7.69 /* Interact with the region's dataspace, specifying a receive window for a
7.70 map operation. Here, a single page is specified. */
7.71
7.72 - client_Dataspace dataspace(r.ds);
7.73 + client_Dataspace dataspace(r->dataspace());
7.74 l4_snd_fpage_t rw_region = {0, l4_fpage(window_base, L4_PAGESHIFT, 0)};
7.75 map_flags_t map_flags = map_flags_for_fault(flags);
7.76
7.77 #if DEBUG
7.78 printf("window_base = %lx; window_size = %lx\n", window_base, window_size);
7.79 printf("region = {%lx, {%lx, %d}}\n", rw_region.snd_base, l4_fpage_memaddr(rw_region.fpage), l4_fpage_size(rw_region.fpage));
7.80 - printf("map(%lx, %lx, %lx) -> %lx\n", offset, hot_spot, map_flags, r.ds);
7.81 + printf("map(%lx, %lx, %lx) -> %lx\n", offset, hot_spot, map_flags, r->dataspace());
7.82 #endif
7.83
7.84 - long err = dataspace.map(offset, hot_spot, map_flags & r.flags, &rw_region);
7.85 + err = dataspace.map(offset, hot_spot, map_flags & r->flags(), &rw_region);
7.86
7.87 /* Indicate an unspecified result, since the mapping should have taken
7.88 place. */
7.89 @@ -147,11 +135,9 @@
7.90 return err;
7.91 }
7.92
7.93 -#if DEBUG
7.94 - printf("not mapped!\n");
7.95 -#endif
7.96 + printf("not mapped at %lx for pc %lx\n", addr, pc);
7.97
7.98 - return -L4_ENOMEM;
7.99 + return err;
7.100 }
7.101
7.102 /* Attach a region for provision when page faults occur. This is required in
7.103 @@ -162,12 +148,21 @@
7.104 l4_cap_idx_t ds, address_t offset,
7.105 unsigned char align)
7.106 {
7.107 - long err = ExecPager::find(start, &size, flags, offset, align);
7.108 + // NOTE: Determine the purpose of offset.
7.109 +
7.110 + (void) offset;
7.111 +
7.112 + MemoryArea *area;
7.113 + long err = ExecPager::find(start, &size, flags, align, &area);
7.114
7.115 if (!err)
7.116 {
7.117 - MappedRegion r(*start, size, flags & L4RE_DS_F_RIGHTS_MASK, ds);
7.118 - add(r);
7.119 + MappedRegion r(*start, *start + size, flags & L4RE_DS_F_RIGHTS_MASK, ds);
7.120 + area->add(r);
7.121 +
7.122 + /* Record dataspaces separately. */
7.123 +
7.124 + _dataspaces.insert(ds);
7.125 }
7.126 else
7.127 ipc_cap_free_um(ds);
7.128 @@ -175,5 +170,34 @@
7.129 return err;
7.130 }
7.131
7.132 +long InternalPager::reserve_area(address_t *start, address_t size,
7.133 + map_flags_t flags, unsigned char align)
7.134 +{
7.135 + MemoryArea *area;
7.136 + long err = ExecPager::find(start, &size, flags, align, &area);
7.137 +
7.138 + if (!err)
7.139 + {
7.140 + /* Add an object acting like a region but without any associated
7.141 + dataspace. */
7.142 +
7.143 + if (flags & L4RE_RM_F_RESERVED)
7.144 + {
7.145 + ReservedMemoryArea r(*start, *start + size);
7.146 + area->add(r);
7.147 + }
7.148 +
7.149 + /* Add an object permitting regions to be added within it. */
7.150 +
7.151 + else
7.152 + {
7.153 + AvailableMemoryArea r(*start, *start + size);
7.154 + area->add(r);
7.155 + }
7.156 + }
7.157 +
7.158 + return err;
7.159 +}
7.160 +
7.161 /* vim: tabstop=2 expandtab shiftwidth=2
7.162 */
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/libexec/lib/src/memory_area.cc Wed Mar 15 00:33:40 2023 +0100
8.3 @@ -0,0 +1,434 @@
8.4 +/*
8.5 + * Memory area functionality.
8.6 + *
8.7 + * Copyright (C) 2022, 2023 Paul Boddie <paul@boddie.org.uk>
8.8 + *
8.9 + * This program is free software; you can redistribute it and/or
8.10 + * modify it under the terms of the GNU General Public License as
8.11 + * published by the Free Software Foundation; either version 2 of
8.12 + * the License, or (at your option) any later version.
8.13 + *
8.14 + * This program is distributed in the hope that it will be useful,
8.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
8.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8.17 + * GNU General Public License for more details.
8.18 + *
8.19 + * You should have received a copy of the GNU General Public License
8.20 + * along with this program; if not, write to the Free Software
8.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
8.22 + * Boston, MA 02110-1301, USA
8.23 + */
8.24 +
8.25 +#include <l4/re/c/rm.h>
8.26 +
8.27 +#include <mem/memory_utils.h>
8.28 +
8.29 +#include "mapped_region.h"
8.30 +
8.31 +
8.32 +
8.33 +/* Copy an area. */
8.34 +
8.35 +MemoryArea *MemoryArea::copy()
8.36 +{
8.37 + return new MemoryArea(_start, _end);
8.38 +}
8.39 +
8.40 +/* In general, a region cannot support other regions. */
8.41 +
8.42 +long MemoryArea::add(MemoryArea &area)
8.43 +{
8.44 + (void) area;
8.45 + return -L4_EPERM;
8.46 +}
8.47 +
8.48 +long MemoryArea::remove(MemoryArea &area)
8.49 +{
8.50 + (void) area;
8.51 + return -L4_EPERM;
8.52 +}
8.53 +
8.54 +/* In general, a region supports a memory access within its bounds. */
8.55 +
8.56 +long MemoryArea::find(address_t addr, MemoryArea **area)
8.57 +{
8.58 + if ((addr >= _start) && (addr < _end))
8.59 + {
8.60 + *area = this;
8.61 + return L4_EOK;
8.62 + }
8.63 + else
8.64 + return -L4_ENOMEM;
8.65 +}
8.66 +
8.67 +/* In general, a region does not support the identification of a location for
8.68 + region insertion. */
8.69 +
8.70 +long MemoryArea::find(address_t *start, address_t *size, map_flags_t flags,
8.71 + unsigned char align, MemoryArea **area)
8.72 +{
8.73 + (void) start; (void) size; (void) flags; (void) align; (void) area;
8.74 + return -L4_ENOMEM;
8.75 +}
8.76 +
8.77 +
8.78 +
8.79 +/* Copy a reserved area. */
8.80 +
8.81 +MemoryArea *ReservedMemoryArea::copy()
8.82 +{
8.83 + return new ReservedMemoryArea(_start, _end);
8.84 +}
8.85 +
8.86 +/* A reserved area does not support any memory access. */
8.87 +
8.88 +long ReservedMemoryArea::find(address_t addr, MemoryArea **area)
8.89 +{
8.90 + (void) addr; (void) area;
8.91 + return -L4_ENOMEM;
8.92 +}
8.93 +
8.94 +
8.95 +
8.96 +/* Discard all allocated areas. */
8.97 +
8.98 +AvailableMemoryArea::~AvailableMemoryArea()
8.99 +{
8.100 + MemoryAreas::iterator it;
8.101 +
8.102 + for (it = _allocated.begin(); it != _allocated.end(); it++)
8.103 + delete *it;
8.104 +
8.105 + _allocated.clear();
8.106 +}
8.107 +
8.108 +/* Copy an unused available memory area. */
8.109 +
8.110 +MemoryArea *AvailableMemoryArea::copy()
8.111 +{
8.112 + return new AvailableMemoryArea(_start, _end);
8.113 +}
8.114 +
8.115 +/* Add an area. */
8.116 +
8.117 +long AvailableMemoryArea::add(MemoryArea &area)
8.118 +{
8.119 + MemoryArea *a = area.copy();
8.120 +
8.121 + _areas[area.area_start()] = a;
8.122 + _allocated.insert(a);
8.123 +
8.124 + return L4_EOK;
8.125 +}
8.126 +
8.127 +/* Remove an area. */
8.128 +
8.129 +long AvailableMemoryArea::remove(MemoryArea &area)
8.130 +{
8.131 + MemoryAreaMap::iterator it = _areas.find(area.area_start());
8.132 +
8.133 + if (it != _areas.end())
8.134 + {
8.135 + _areas.erase(it);
8.136 +
8.137 + MemoryAreas::iterator ita = _allocated.find(it->second);
8.138 +
8.139 + if (ita != _allocated.end())
8.140 + {
8.141 + delete *ita;
8.142 + _allocated.erase(ita);
8.143 + }
8.144 + }
8.145 +
8.146 + return L4_EOK;
8.147 +}
8.148 +
8.149 +/* Find an region able to support a memory access. */
8.150 +
8.151 +long AvailableMemoryArea::find(address_t addr, MemoryArea **area)
8.152 +{
8.153 + MemoryAreaMap::iterator it = _areas.upper_bound(addr);
8.154 +
8.155 + /* Consider any area preceding or encompassing the desired address. */
8.156 +
8.157 + if (it != _areas.begin())
8.158 + {
8.159 + it--;
8.160 +
8.161 + /* Test whether the desired region start is encompassed by the preceding
8.162 + area. */
8.163 +
8.164 + MemoryArea *r = it->second;
8.165 +
8.166 + if (r->supports(addr))
8.167 + return r->find(addr, area);
8.168 + }
8.169 +
8.170 + /* Otherwise, no area within this area supports the address. */
8.171 +
8.172 + return -L4_ENOMEM;
8.173 +}
8.174 +
8.175 +/* Find an area suitable for attaching a memory region. */
8.176 +
8.177 +long AvailableMemoryArea::find(address_t *start, address_t *size,
8.178 + map_flags_t flags, unsigned char align,
8.179 + MemoryArea **area)
8.180 +{
8.181 + /* Obtain the alignment increment and a properly aligned size. */
8.182 +
8.183 + address_t increment = 1UL << align;
8.184 + address_t region_size = round(*size, increment);
8.185 +
8.186 + /* Align any desired location. */
8.187 +
8.188 + address_t region_start = trunc(*start, increment);
8.189 +
8.190 + /* Enforce a minimum address. */
8.191 +
8.192 + if (region_start < _start)
8.193 + region_start = round(_start, increment);
8.194 +
8.195 + /* Search for existing regions after the desired, conformant start address. */
8.196 +
8.197 + MemoryAreaMap::iterator it = _areas.upper_bound(region_start);
8.198 +
8.199 + /* Consider any area preceding or encompassing the desired address. */
8.200 +
8.201 + if (it != _areas.begin())
8.202 + {
8.203 + MemoryAreaMap::iterator next = it;
8.204 +
8.205 + /* Step back to the preceding area to get its details. */
8.206 +
8.207 + it--;
8.208 + MemoryArea *pr = it->second;
8.209 + it = next;
8.210 +
8.211 + /* Test whether the desired region start is encompassed by the preceding
8.212 + area. */
8.213 +
8.214 + if (region_start < pr->area_end())
8.215 + {
8.216 + /* Where the preceding area is mapped or a reserved area, adjust the start
8.217 + of any search range. If an exact request is made for a region, deny the
8.218 + request. */
8.219 +
8.220 + if (pr->is_mapped() || pr->is_reserved())
8.221 + {
8.222 + if (!(flags & L4RE_RM_F_SEARCH_ADDR))
8.223 + return -L4_ENOMEM;
8.224 +
8.225 + region_start = round(pr->area_end(), increment);
8.226 + }
8.227 +
8.228 + /* Where the preceding area is an area within which regions might be
8.229 + established, search within that area. */
8.230 +
8.231 + else
8.232 + return pr->find(start, size, flags, align, area);
8.233 + }
8.234 + }
8.235 +
8.236 + /* Consider the regions following the current region start candidate. */
8.237 +
8.238 + MemoryArea *r;
8.239 +
8.240 + while ((it != _areas.end()) && !(_end && ((region_start + region_size) > _end)))
8.241 + {
8.242 + r = it->second;
8.243 +
8.244 + /* Obtain the limit of available space being considered. */
8.245 +
8.246 + address_t end_limit = r->area_start();
8.247 +
8.248 + /* Test if not enough space exists between the preceding region (or start of
8.249 + memory) and the current region. */
8.250 +
8.251 + if ((region_start + region_size) > end_limit)
8.252 + {
8.253 + /* If an exact request is made for a region, deny the request. */
8.254 +
8.255 + if (!(flags & L4RE_RM_F_SEARCH_ADDR))
8.256 + return -L4_ENOMEM;
8.257 +
8.258 + /* Otherwise, investigate subsequent regions if not enough space exists
8.259 + between the preceding region (or start of memory) and the current
8.260 + region. */
8.261 +
8.262 + region_start = round(r->area_end(), increment);
8.263 + it++;
8.264 + }
8.265 +
8.266 + /* Otherwise, the region can be positioned. */
8.267 +
8.268 + else
8.269 + break;
8.270 + }
8.271 +
8.272 + /* Test for enough memory constrained by any predefined limit. */
8.273 +
8.274 + if (_end && ((region_start + region_size) > _end))
8.275 + return -L4_ENOMEM;
8.276 +
8.277 + /* Return the configured start and size. */
8.278 +
8.279 + *start = region_start;
8.280 + *size = region_size;
8.281 +
8.282 + /* Return the area within which any region will be added. */
8.283 +
8.284 + *area = this;
8.285 +
8.286 + return L4_EOK;
8.287 +}
8.288 +
8.289 +/* Obtain a recursive iterator over a memory area. */
8.290 +
8.291 +AvailableMemoryArea::iterator AvailableMemoryArea::begin()
8.292 +{
8.293 + return AvailableMemoryArea::iterator(_areas.begin(), _areas.end());
8.294 +}
8.295 +
8.296 +AvailableMemoryArea::iterator AvailableMemoryArea::end()
8.297 +{
8.298 + return AvailableMemoryArea::iterator(_areas.end(), _areas.end());
8.299 +}
8.300 +
8.301 +MemoryAreaMap::iterator AvailableMemoryArea::areas_begin()
8.302 +{
8.303 + return _areas.begin();
8.304 +}
8.305 +
8.306 +MemoryAreaMap::iterator AvailableMemoryArea::areas_end()
8.307 +{
8.308 + return _areas.end();
8.309 +}
8.310 +
8.311 +
8.312 +
8.313 +/* Initialise a recursive iterator over a memory area. */
8.314 +
8.315 +AvailableMemoryArea::iterator::iterator(MemoryAreaMap::iterator it,
8.316 + MemoryAreaMap::iterator end)
8.317 +{
8.318 + _iterators.push(it);
8.319 + _ends.push(end);
8.320 +
8.321 + /* Descend to the first non-container area. */
8.322 +
8.323 + descend_all();
8.324 +}
8.325 +
8.326 +AvailableMemoryArea::iterator::iterator()
8.327 +{
8.328 +}
8.329 +
8.330 +/* Return the current underlying iterator. */
8.331 +
8.332 +MemoryAreaMap::iterator &AvailableMemoryArea::iterator::area_iterator()
8.333 +{
8.334 + return _iterators.top();
8.335 +}
8.336 +
8.337 +/* Return the end point of the current underlying iterator. */
8.338 +
8.339 +MemoryAreaMap::iterator &AvailableMemoryArea::iterator::area_end()
8.340 +{
8.341 + return _ends.top();
8.342 +}
8.343 +
8.344 +/* Return the current area. */
8.345 +
8.346 +MemoryArea *AvailableMemoryArea::iterator::operator *()
8.347 +{
8.348 + return area_iterator()->second;
8.349 +}
8.350 +
8.351 +/* Return whether this iterator references the same area as the other
8.352 + iterator. */
8.353 +
8.354 +bool AvailableMemoryArea::iterator::operator ==(AvailableMemoryArea::iterator other)
8.355 +{
8.356 + return area_iterator() == other.area_iterator();
8.357 +}
8.358 +
8.359 +/* Return whether this iterator references a different area to the other
8.360 + iterator. */
8.361 +
8.362 +bool AvailableMemoryArea::iterator::operator !=(AvailableMemoryArea::iterator other)
8.363 +{
8.364 + return area_iterator() != other.area_iterator();
8.365 +}
8.366 +
8.367 +/* Advance this iterator to the next area. */
8.368 +
8.369 +AvailableMemoryArea::iterator &AvailableMemoryArea::iterator::operator ++()
8.370 +{
8.371 + /* Advance the area iterator. */
8.372 +
8.373 + area_iterator()++;
8.374 +
8.375 + /* Descend to the next non-container area. */
8.376 +
8.377 + descend_all();
8.378 +
8.379 + return *this;
8.380 +}
8.381 +
8.382 +AvailableMemoryArea::iterator &AvailableMemoryArea::iterator::operator ++(int)
8.383 +{
8.384 + return ++(*this);
8.385 +}
8.386 +
8.387 +/* Advance this iterator to the next area not containing other areas. */
8.388 +
8.389 +void AvailableMemoryArea::iterator::descend_all()
8.390 +{
8.391 + while ((area_iterator() != area_end()) || (_iterators.size() > 1))
8.392 + {
8.393 + /* Handle empty areas by ascending to refer to the area. */
8.394 +
8.395 + if (area_iterator() == area_end())
8.396 + {
8.397 + ascend();
8.398 + break;
8.399 + }
8.400 +
8.401 + MemoryArea *r = area_iterator()->second;
8.402 +
8.403 + /* Handle areas by descending into them. */
8.404 +
8.405 + if (!r->is_reserved() && !r->is_mapped())
8.406 + descend();
8.407 +
8.408 + /* Yield any non-container areas. */
8.409 +
8.410 + else
8.411 + break;
8.412 + }
8.413 +}
8.414 +
8.415 +/* Ascend from a memory area. */
8.416 +
8.417 +void AvailableMemoryArea::iterator::ascend()
8.418 +{
8.419 + _iterators.pop();
8.420 + _ends.pop();
8.421 +}
8.422 +
8.423 +/* Descend into a memory area. */
8.424 +
8.425 +void AvailableMemoryArea::iterator::descend()
8.426 +{
8.427 + AvailableMemoryArea *a = dynamic_cast<AvailableMemoryArea *>(area_iterator()->second);
8.428 +
8.429 + if (a != NULL)
8.430 + {
8.431 + _iterators.push(a->areas_begin());
8.432 + _ends.push(a->areas_end());
8.433 + }
8.434 +}
8.435 +
8.436 +/* vim: tabstop=2 expandtab shiftwidth=2
8.437 +*/
9.1 --- a/libexec/lib/src/pager.cc Tue Mar 14 23:51:57 2023 +0100
9.2 +++ b/libexec/lib/src/pager.cc Wed Mar 15 00:33:40 2023 +0100
9.3 @@ -20,7 +20,6 @@
9.4 */
9.5
9.6 #include <l4/re/env.h>
9.7 -#include <l4/re/c/rm.h>
9.8
9.9 #include <mem/memory_utils.h>
9.10
9.11 @@ -31,7 +30,7 @@
9.12 /* Initialise common functionality. */
9.13
9.14 ExecPager::ExecPager(address_t start, address_t end)
9.15 -: _start(start), _end(end)
9.16 +: _area(start, end)
9.17 {
9.18 }
9.19
9.20 @@ -43,118 +42,34 @@
9.21
9.22
9.23
9.24 -/* Add a region to the pager. */
9.25 +/* Add an area to the pager. */
9.26
9.27 -void ExecPager::add(MappedRegion ®ion)
9.28 +void ExecPager::add(MemoryArea &area)
9.29 {
9.30 - _regions[region.start] = region;
9.31 + _area.add(area);
9.32 }
9.33
9.34 -/* Remove a region from the pager. */
9.35 +/* Remove an area from the pager. */
9.36
9.37 -void ExecPager::remove(MappedRegion ®ion)
9.38 +void ExecPager::remove(MemoryArea &area)
9.39 {
9.40 - _regions.erase(region.start);
9.41 + _area.remove(area);
9.42 }
9.43
9.44
9.45
9.46 -/* Attach a region for provision when page faults occur. */
9.47 +/* Find an area suitable for attaching a memory region. */
9.48
9.49 long ExecPager::find(address_t *start, address_t *size, map_flags_t flags,
9.50 - address_t offset, unsigned char align)
9.51 + unsigned char align, MemoryArea **area)
9.52 {
9.53 if (align < L4_PAGESHIFT)
9.54 align = L4_PAGESHIFT;
9.55
9.56 - /* Obtain the alignment increment and a properly aligned size. */
9.57 -
9.58 - address_t increment = 1UL << align;
9.59 - address_t region_size = round(*size, increment);
9.60 -
9.61 - /* Either attempt to find an address for the specified region, starting from
9.62 + /* Attempt to find an address for the specified region, starting from
9.63 any indicated address. */
9.64
9.65 - if (flags & L4RE_RM_F_SEARCH_ADDR)
9.66 - {
9.67 - /* Align any desired location. */
9.68 -
9.69 - address_t region_start = trunc(*start, increment);
9.70 -
9.71 - /* Enforce a minimum address. */
9.72 -
9.73 - if (region_start < _start)
9.74 - region_start = round(_start, increment);
9.75 -
9.76 - /* Search for existing regions after the desired, conformant address. */
9.77 -
9.78 - MappedRegions::iterator it = _regions.upper_bound(region_start);
9.79 -
9.80 - /* Consider any region preceding or encompassing the desired address. */
9.81 -
9.82 - if (it != _regions.begin())
9.83 - {
9.84 - MappedRegions::iterator next = it;
9.85 -
9.86 - /* Step back to the preceding region to get its details. */
9.87 -
9.88 - it--;
9.89 - MappedRegion &pr = it->second;
9.90 - address_t previous_end = pr.start + pr.size;
9.91 - it = next;
9.92 -
9.93 - /* The preceding region may displace the desired region location if it
9.94 - is encompassed by the region. */
9.95 -
9.96 - if (region_start < previous_end)
9.97 - region_start = round(previous_end, increment);
9.98 - }
9.99 -
9.100 - /* Consider the regions following the current region start candidate. */
9.101 -
9.102 - while ((it != _regions.end()) && !(_end && ((region_start + region_size) > _end)))
9.103 - {
9.104 - MappedRegion &r = it->second;
9.105 -
9.106 - /* Obtain the limit of available space being considered. */
9.107 -
9.108 - address_t end_limit = r.start;
9.109 -
9.110 - /* Investigate subsequent regions if not enough space exists between the
9.111 - preceding region (or start of memory) and the current region. */
9.112 -
9.113 - if ((region_start + region_size) > end_limit)
9.114 - {
9.115 - region_start = round(r.start + r.size, increment);
9.116 - it++;
9.117 - }
9.118 -
9.119 - /* Otherwise, the region can be positioned. */
9.120 -
9.121 - else
9.122 - break;
9.123 - }
9.124 -
9.125 - /* Test for enough memory constrained by any predefined limit. */
9.126 -
9.127 - if (_end && ((region_start + region_size) > _end))
9.128 - return -L4_ENOMEM;
9.129 -
9.130 - /* Return the configured start and size. */
9.131 -
9.132 - *start = region_start;
9.133 - *size = region_size;
9.134 - return L4_EOK;
9.135 - }
9.136 -
9.137 - /* Or attempt to add the specified region at a specific address. */
9.138 -
9.139 - else
9.140 - {
9.141 - // NOTE: To be implemented.
9.142 -
9.143 - return -L4_ENOMEM;
9.144 - }
9.145 + return _area.find(start, size, flags, align, area);
9.146 }
9.147
9.148 /* vim: tabstop=2 expandtab shiftwidth=2
10.1 --- a/libexec/lib/src/segment.cc Tue Mar 14 23:51:57 2023 +0100
10.2 +++ b/libexec/lib/src/segment.cc Wed Mar 15 00:33:40 2023 +0100
10.3 @@ -141,7 +141,8 @@
10.4
10.5 MappedRegion &Segment::region()
10.6 {
10.7 - _region = MappedRegion(_region_base, _region_allocated_size, region_flags(), _ds, (l4_addr_t) _buf);
10.8 + _region = MappedRegion(_region_base, _region_base + _region_allocated_size,
10.9 + region_flags(), _ds, (l4_addr_t) _buf);
10.10 return _region;
10.11 }
10.12
11.1 --- a/libexec/rm/region_mapper.cc Tue Mar 14 23:51:57 2023 +0100
11.2 +++ b/libexec/rm/region_mapper.cc Wed Mar 15 00:33:40 2023 +0100
11.3 @@ -57,8 +57,8 @@
11.4
11.5 for (; region && (region->ds != L4_INVALID_CAP); region++)
11.6 {
11.7 - printf("Adding region: {%lx, %llx, %lx, %lx}\n", region->start, region->size, region->flags, region->ds);
11.8 - MappedRegion r(region->start, region->size, region->flags, region->ds);
11.9 + printf("Adding region: {%lx, %llx, %lx, %lx}\n", region->start, region->start + region->size, region->flags, region->ds);
11.10 + MappedRegion r(region->start, region->start + region->size, region->flags, region->ds);
11.11 exec_pager.add(r);
11.12 }
11.13