# HG changeset patch # User Paul Boddie # Date 1678836820 -3600 # Node ID bae2ddb47ecd31794c5bee3bdacfce8f76ab722c # Parent d0e6f1d3f3377c44dc39a9d1ce28745208f16225 Introduced support for reserve_area in the internal pager along with different kinds of memory area. This permits the execution of threaded programs. diff -r d0e6f1d3f337 -r bae2ddb47ecd libexec/include/exec/internal_pager.h --- a/libexec/include/exec/internal_pager.h Tue Mar 14 23:51:57 2023 +0100 +++ b/libexec/include/exec/internal_pager.h Wed Mar 15 00:33:40 2023 +0100 @@ -58,6 +58,9 @@ virtual long attach(address_t *start, address_t size, map_flags_t flags, l4_cap_idx_t ds, address_t offset, unsigned char align); + + virtual long reserve_area(address_t *start, address_t size, map_flags_t flags, + unsigned char align); }; /* vim: tabstop=2 expandtab shiftwidth=2 diff -r d0e6f1d3f337 -r bae2ddb47ecd libexec/include/exec/mapped_region.h --- a/libexec/include/exec/mapped_region.h Tue Mar 14 23:51:57 2023 +0100 +++ b/libexec/include/exec/mapped_region.h Wed Mar 15 00:33:40 2023 +0100 @@ -1,7 +1,7 @@ /* * Mapped memory region support. * - * Copyright (C) 2022 Paul Boddie + * Copyright (C) 2022, 2023 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -23,32 +23,51 @@ #include +#include #include /* A mapped region abstraction. */ -class MappedRegion +class MappedRegion : public MemoryArea { +protected: + l4_umword_t _flags; + l4_cap_idx_t _ds; + address_t _ds_start; + public: - l4_addr_t start; - offset_t size; - l4_umword_t flags; - l4_cap_idx_t ds; - l4_addr_t ds_start; - explicit MappedRegion() - : start(0), size(0), flags(0), ds(L4_INVALID_CAP), ds_start(0) + : MemoryArea(), _flags(0), _ds(L4_INVALID_CAP), _ds_start(0) { } - explicit MappedRegion(l4_addr_t start, l4_addr_t size, + explicit MappedRegion(address_t start, address_t end, l4_umword_t flags, l4_cap_idx_t ds = L4_INVALID_CAP, - l4_addr_t ds_start = 0) - : start(start), size(size), flags(flags), ds(ds), ds_start(ds_start) + address_t ds_start = 0) + : MemoryArea(start, end), _flags(flags), _ds(ds), _ds_start(ds_start) { } + + virtual MemoryArea *copy() + { return new MappedRegion(_start, _end, _flags, _ds, _ds_start); } + + /* Access to area properties. */ + + virtual l4_umword_t flags() + { return _flags; } + + virtual l4_cap_idx_t dataspace() + { return _ds; } + + virtual address_t dataspace_start() + { return _ds_start; } + + /* Return whether the area provides a mapped region. */ + + virtual bool is_mapped() + { return true; } }; /* vim: tabstop=2 expandtab shiftwidth=2 diff -r d0e6f1d3f337 -r bae2ddb47ecd libexec/include/exec/memory_area.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/include/exec/memory_area.h Wed Mar 15 00:33:40 2023 +0100 @@ -0,0 +1,218 @@ +/* + * Memory area support. + * + * Copyright (C) 2022, 2023 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include +#include + +#include + +#include + + + +/* A memory area abstraction. */ + +class MemoryArea +{ +protected: + address_t _start, _end; + +public: + explicit MemoryArea() + : _start(0), _end(0) + { + } + + explicit MemoryArea(address_t start, address_t end) + : _start(start), _end(end) + { + } + + virtual ~MemoryArea() + { + } + + virtual MemoryArea *copy(); + + /* Access to area properties. */ + + virtual address_t area_start() + { return _start; } + + virtual address_t area_end() + { return _end; } + + virtual l4_umword_t flags() + { return 0; } + + virtual l4_cap_idx_t dataspace() + { return L4_INVALID_CAP; } + + virtual address_t dataspace_start() + { return 0; } + + /* Return whether the area supports the given address. */ + + virtual bool supports(address_t addr) + { return (_start <= addr) && (addr < _end); } + + /* Return whether an area is reserved and therefore cannot be mapped. */ + + virtual bool is_reserved() + { return false; } + + /* Return whether the area provides a mapped region. */ + + virtual bool is_mapped() + { return false; } + + /* Support for populating areas. */ + + virtual long add(MemoryArea &area); + + virtual long remove(MemoryArea &area); + + /* Support for finding regions. */ + + virtual long find(address_t addr, MemoryArea **area); + + /* Support for finding areas. */ + + virtual long find(address_t *start, address_t *size, map_flags_t flags, + unsigned char align, MemoryArea **area); +}; + + + +/* A reserved area abstraction. */ + +class ReservedMemoryArea : public MemoryArea +{ +public: + explicit ReservedMemoryArea(address_t start, address_t end) + : MemoryArea(start, end) + { + } + + virtual MemoryArea *copy(); + + /* Return whether an area is reserved and therefore cannot be mapped. */ + + virtual bool is_reserved() + { return true; } + + /* Support for finding areas. */ + + virtual long find(address_t addr, MemoryArea **area); +}; + + + +/* Collection types. */ + +typedef std::map MemoryAreaMap; +typedef std::set MemoryAreas; + + + +/* A memory area containing other areas. */ + +class AvailableMemoryArea : public MemoryArea +{ +protected: + MemoryAreaMap _areas; + MemoryAreas _allocated; + +public: + explicit AvailableMemoryArea(address_t start, address_t end) + : MemoryArea(start, end) + { + } + + virtual ~AvailableMemoryArea(); + + virtual MemoryArea *copy(); + + /* Support for populating areas. */ + + virtual long add(MemoryArea &area); + + virtual long remove(MemoryArea &area); + + /* Support for finding areas. */ + + virtual long find(address_t addr, MemoryArea **area); + + virtual long find(address_t *start, address_t *size, map_flags_t flags, + unsigned char align, MemoryArea **area); + + /* A recursive iterator over a memory area. */ + + class iterator + { + protected: + std::stack _iterators, _ends; + + void ascend(); + + void descend(); + + void descend_all(); + + public: + explicit iterator(); + + explicit iterator(MemoryAreaMap::iterator it, + MemoryAreaMap::iterator end); + + MemoryArea *operator *(); + + iterator &operator ++(); + + iterator &operator ++(int); + + bool operator ==(iterator other); + + bool operator !=(iterator other); + + /* Access to the underlying iterators. */ + + MemoryAreaMap::iterator &area_iterator(); + + MemoryAreaMap::iterator &area_end(); + }; + + /* Iteration methods. */ + + virtual iterator begin(); + + virtual iterator end(); + + virtual MemoryAreaMap::iterator areas_begin(); + + virtual MemoryAreaMap::iterator areas_end(); +}; + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r d0e6f1d3f337 -r bae2ddb47ecd libexec/include/exec/pager.h --- a/libexec/include/exec/pager.h Tue Mar 14 23:51:57 2023 +0100 +++ b/libexec/include/exec/pager.h Wed Mar 15 00:33:40 2023 +0100 @@ -21,15 +21,15 @@ #pragma once -#include +#include -#include +#include -/* Collection types. */ +/* Collection definitions. */ -typedef std::map MappedRegions; +typedef std::set Capabilities; @@ -38,14 +38,19 @@ class ExecPager { protected: - address_t _start, _end; + + /* Top-level area containing other areas and regions. */ + + AvailableMemoryArea _area; + + /* Dataspace capabilities associated with regions. */ + + Capabilities _dataspaces; /* Region manager/mapper functionality. */ - MappedRegions _regions; - virtual long find(address_t *start, address_t *size, map_flags_t flags, - address_t offset, unsigned char align); + unsigned char align, MemoryArea **area); public: explicit ExecPager(address_t start = 0, address_t end = 0); @@ -54,9 +59,9 @@ /* Region management methods. */ - virtual void add(MappedRegion ®ion); + virtual void add(MemoryArea &area); - virtual void remove(MappedRegion ®ion); + virtual void remove(MemoryArea &area); /* Notification methods. */ diff -r d0e6f1d3f337 -r bae2ddb47ecd libexec/lib/src/Makefile --- a/libexec/lib/src/Makefile Tue Mar 14 23:51:57 2023 +0100 +++ b/libexec/lib/src/Makefile Wed Mar 15 00:33:40 2023 +0100 @@ -28,8 +28,11 @@ # Normal source files. PLAIN_SRC_CC = \ - common.cc elf.cc external_pager.cc \ - internal_pager.cc memory.cc pager.cc \ + common.cc elf.cc \ + external_pager.cc \ + internal_pager.cc \ + memory.cc memory_area.cc \ + pager.cc \ process.cc process_creating.cc \ process_creator_context_resource.cc \ process_creator_resource.cc \ diff -r d0e6f1d3f337 -r bae2ddb47ecd libexec/lib/src/external_pager.cc --- a/libexec/lib/src/external_pager.cc Tue Mar 14 23:51:57 2023 +0100 +++ b/libexec/lib/src/external_pager.cc Wed Mar 15 00:33:40 2023 +0100 @@ -58,7 +58,7 @@ void ExternalPager::close() { - printf("Pager closing...\n"); + printf("External pager closing...\n"); /* Remove pager regions to avoid unmapping them twice. */ @@ -77,15 +77,22 @@ /* Unmap all remaining regions. */ - MappedRegions::iterator it; + AvailableMemoryArea::iterator it; - for (it = _regions.begin(); it != _regions.end(); it++) + for (it = _area.begin(); it != _area.end(); it++) { - MappedRegion &r = it->second; + MemoryArea *r = *it; + + if (r->is_mapped()) + ipc_detach_dataspace((void *) r->dataspace_start()); + } - ipc_detach_dataspace((void *) r.ds_start); - ipc_cap_free_um(r.ds); - } + /* Free all capabilities. */ + + Capabilities::iterator itc; + + for (itc = _dataspaces.begin(); itc != _dataspaces.end(); itc++) + ipc_cap_free_um(*itc); /* Remove the created task. */ @@ -172,61 +179,47 @@ printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags); #endif - /* Find the first region whose start address is beyond the fault address, - testing if any immediately preceding region contains the fault address. */ - - MappedRegions::iterator it = _regions.upper_bound(addr); + /* Obtain a region supporting the fault address. */ - if (it != _regions.begin()) - it--; - else - { - printf("not mapped at %lx for pc %lx\n", addr, pc); - return -L4_ENOMEM; - } + MemoryArea *r; + long err = _area.find(addr, &r); - /* Obtain the region and test if it contains the fault address. */ - - MappedRegion &r = it->second; - - if ((addr >= r.start) && (addr < r.start + r.size)) + if (!err) { l4_addr_t page_addr = trunc(addr, L4_PAGESIZE); map_flags_t map_flags = map_flags_for_fault(flags); - region->fpage = l4_fpage(r.ds_start + (page_addr - r.start), L4_PAGESHIFT, map_flags & r.flags); + region->fpage = l4_fpage(r->dataspace_start() + (page_addr - r->area_start()), L4_PAGESHIFT, map_flags & r->flags()); region->snd_base = page_addr; #if DEBUG printf("%lx...%lx from %lx...%lx offset %lx size %d rights %x ds %lx\n", - r.start, region->snd_base, - r.ds_start, l4_fpage_memaddr(region->fpage), - addr - r.start, + r->area_start(), region->snd_base, + r->dataspace_start(), l4_fpage_memaddr(region->fpage), + addr - r->area_start(), l4_fpage_size(region->fpage), l4_fpage_rights(region->fpage), - r.ds); + r->dataspace()); printf("%lx -> ", addr); for (unsigned int i = 0; i < sizeof(l4_umword_t); i++) - printf("%02x", *((unsigned char *)(r.ds_start + (addr - r.start) + i))); + printf("%02x", *((unsigned char *)(r->dataspace_start() + (addr - r->area_start()) + i))); printf("\n"); #endif - if (r.flags & L4RE_RM_F_W) - l4_touch_rw((const void *) (r.ds_start + (page_addr - r.start)), L4_PAGESIZE); + if (r->flags() & L4RE_RM_F_W) + l4_touch_rw((const void *) (r->dataspace_start() + (page_addr - r->area_start())), L4_PAGESIZE); else - l4_touch_ro((const void *) (r.ds_start + (page_addr - r.start)), L4_PAGESIZE); + l4_touch_ro((const void *) (r->dataspace_start() + (page_addr - r->area_start())), L4_PAGESIZE); return L4_EOK; } -#if DEBUG - printf("not mapped!\n"); -#endif + printf("not mapped at %lx for pc %lx\n", addr, pc); - return -L4_ENOMEM; + return err; } /* Attach a region for provision when page faults occur. This is required in @@ -237,7 +230,12 @@ l4_cap_idx_t ds, address_t offset, unsigned char align) { - long err = ExecPager::find(start, &size, flags, offset, align); + // NOTE: Determine the purpose of offset. + + (void) offset; + + MemoryArea *area; + long err = ExecPager::find(start, &size, flags, align, &area); /* Without an error, attach the dataspace. */ @@ -257,8 +255,12 @@ l4_touch_rw((const void *) ds_start, size); - MappedRegion r(*start, size, flags & L4RE_DS_F_RIGHTS_MASK, ds, ds_start); - add(r); + MappedRegion r(*start, *start + size, flags & L4RE_DS_F_RIGHTS_MASK, ds, ds_start); + area->add(r); + + /* Record dataspaces separately. */ + + _dataspaces.insert(ds); } /* Discard the imported dataspace if its region cannot be accommodated. */ @@ -281,6 +283,8 @@ if (sig == 0) { + printf("Signal from task.\n"); + /* Once the program exits, the IPC gate connecting the program with its internal pager can be released. */ diff -r d0e6f1d3f337 -r bae2ddb47ecd libexec/lib/src/internal_pager.cc --- a/libexec/lib/src/internal_pager.cc Tue Mar 14 23:51:57 2023 +0100 +++ b/libexec/lib/src/internal_pager.cc Wed Mar 15 00:33:40 2023 +0100 @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -31,6 +32,7 @@ #include "dataspace_client.h" #include "internal_pager.h" +#include "mapped_region.h" #include "pager_object_server.h" @@ -61,14 +63,10 @@ /* Unmap all regions. */ - MappedRegions::iterator it; + Capabilities::iterator itc; - for (it = _regions.begin(); it != _regions.end(); it++) - { - MappedRegion &r = it->second; - - ipc_cap_free_um(r.ds); - } + for (itc = _dataspaces.begin(); itc != _dataspaces.end(); itc++) + ipc_cap_free_um(*itc); } @@ -101,43 +99,33 @@ printf("regs = %p\n; regs->user[0] = %lx\n", regs, regs->user[0]); #endif - /* Find the first region whose start address is beyond the fault address, - testing if any immediately preceding region contains the fault address. */ - - MappedRegions::iterator it = _regions.upper_bound(addr); + /* Obtain a region supporting the fault address. */ - if (it != _regions.begin()) - it--; - else - { - printf("not mapped at %lx for pc %lx\n", addr, pc); - return -L4_ENOMEM; - } + MemoryArea *r; + long err = _area.find(addr, &r); - MappedRegion &r = it->second; - - if ((addr >= r.start) && (addr < r.start + r.size)) + if (!err) { address_t window_size = L4_PAGESIZE; address_t window_base = trunc(addr, window_size); - address_t offset = addr - r.start; + address_t offset = addr - r->area_start(); address_t page_addr = trunc(addr, L4_PAGESIZE); address_t hot_spot = page_addr - window_base; /* Interact with the region's dataspace, specifying a receive window for a map operation. Here, a single page is specified. */ - client_Dataspace dataspace(r.ds); + client_Dataspace dataspace(r->dataspace()); l4_snd_fpage_t rw_region = {0, l4_fpage(window_base, L4_PAGESHIFT, 0)}; map_flags_t map_flags = map_flags_for_fault(flags); #if DEBUG printf("window_base = %lx; window_size = %lx\n", window_base, window_size); printf("region = {%lx, {%lx, %d}}\n", rw_region.snd_base, l4_fpage_memaddr(rw_region.fpage), l4_fpage_size(rw_region.fpage)); - printf("map(%lx, %lx, %lx) -> %lx\n", offset, hot_spot, map_flags, r.ds); + printf("map(%lx, %lx, %lx) -> %lx\n", offset, hot_spot, map_flags, r->dataspace()); #endif - long err = dataspace.map(offset, hot_spot, map_flags & r.flags, &rw_region); + err = dataspace.map(offset, hot_spot, map_flags & r->flags(), &rw_region); /* Indicate an unspecified result, since the mapping should have taken place. */ @@ -147,11 +135,9 @@ return err; } -#if DEBUG - printf("not mapped!\n"); -#endif + printf("not mapped at %lx for pc %lx\n", addr, pc); - return -L4_ENOMEM; + return err; } /* Attach a region for provision when page faults occur. This is required in @@ -162,12 +148,21 @@ l4_cap_idx_t ds, address_t offset, unsigned char align) { - long err = ExecPager::find(start, &size, flags, offset, align); + // NOTE: Determine the purpose of offset. + + (void) offset; + + MemoryArea *area; + long err = ExecPager::find(start, &size, flags, align, &area); if (!err) { - MappedRegion r(*start, size, flags & L4RE_DS_F_RIGHTS_MASK, ds); - add(r); + MappedRegion r(*start, *start + size, flags & L4RE_DS_F_RIGHTS_MASK, ds); + area->add(r); + + /* Record dataspaces separately. */ + + _dataspaces.insert(ds); } else ipc_cap_free_um(ds); @@ -175,5 +170,34 @@ return err; } +long InternalPager::reserve_area(address_t *start, address_t size, + map_flags_t flags, unsigned char align) +{ + MemoryArea *area; + long err = ExecPager::find(start, &size, flags, align, &area); + + if (!err) + { + /* Add an object acting like a region but without any associated + dataspace. */ + + if (flags & L4RE_RM_F_RESERVED) + { + ReservedMemoryArea r(*start, *start + size); + area->add(r); + } + + /* Add an object permitting regions to be added within it. */ + + else + { + AvailableMemoryArea r(*start, *start + size); + area->add(r); + } + } + + return err; +} + /* vim: tabstop=2 expandtab shiftwidth=2 */ diff -r d0e6f1d3f337 -r bae2ddb47ecd libexec/lib/src/memory_area.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/lib/src/memory_area.cc Wed Mar 15 00:33:40 2023 +0100 @@ -0,0 +1,434 @@ +/* + * Memory area functionality. + * + * Copyright (C) 2022, 2023 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include + +#include "mapped_region.h" + + + +/* Copy an area. */ + +MemoryArea *MemoryArea::copy() +{ + return new MemoryArea(_start, _end); +} + +/* In general, a region cannot support other regions. */ + +long MemoryArea::add(MemoryArea &area) +{ + (void) area; + return -L4_EPERM; +} + +long MemoryArea::remove(MemoryArea &area) +{ + (void) area; + return -L4_EPERM; +} + +/* In general, a region supports a memory access within its bounds. */ + +long MemoryArea::find(address_t addr, MemoryArea **area) +{ + if ((addr >= _start) && (addr < _end)) + { + *area = this; + return L4_EOK; + } + else + return -L4_ENOMEM; +} + +/* In general, a region does not support the identification of a location for + region insertion. */ + +long MemoryArea::find(address_t *start, address_t *size, map_flags_t flags, + unsigned char align, MemoryArea **area) +{ + (void) start; (void) size; (void) flags; (void) align; (void) area; + return -L4_ENOMEM; +} + + + +/* Copy a reserved area. */ + +MemoryArea *ReservedMemoryArea::copy() +{ + return new ReservedMemoryArea(_start, _end); +} + +/* A reserved area does not support any memory access. */ + +long ReservedMemoryArea::find(address_t addr, MemoryArea **area) +{ + (void) addr; (void) area; + return -L4_ENOMEM; +} + + + +/* Discard all allocated areas. */ + +AvailableMemoryArea::~AvailableMemoryArea() +{ + MemoryAreas::iterator it; + + for (it = _allocated.begin(); it != _allocated.end(); it++) + delete *it; + + _allocated.clear(); +} + +/* Copy an unused available memory area. */ + +MemoryArea *AvailableMemoryArea::copy() +{ + return new AvailableMemoryArea(_start, _end); +} + +/* Add an area. */ + +long AvailableMemoryArea::add(MemoryArea &area) +{ + MemoryArea *a = area.copy(); + + _areas[area.area_start()] = a; + _allocated.insert(a); + + return L4_EOK; +} + +/* Remove an area. */ + +long AvailableMemoryArea::remove(MemoryArea &area) +{ + MemoryAreaMap::iterator it = _areas.find(area.area_start()); + + if (it != _areas.end()) + { + _areas.erase(it); + + MemoryAreas::iterator ita = _allocated.find(it->second); + + if (ita != _allocated.end()) + { + delete *ita; + _allocated.erase(ita); + } + } + + return L4_EOK; +} + +/* Find an region able to support a memory access. */ + +long AvailableMemoryArea::find(address_t addr, MemoryArea **area) +{ + MemoryAreaMap::iterator it = _areas.upper_bound(addr); + + /* Consider any area preceding or encompassing the desired address. */ + + if (it != _areas.begin()) + { + it--; + + /* Test whether the desired region start is encompassed by the preceding + area. */ + + MemoryArea *r = it->second; + + if (r->supports(addr)) + return r->find(addr, area); + } + + /* Otherwise, no area within this area supports the address. */ + + return -L4_ENOMEM; +} + +/* Find an area suitable for attaching a memory region. */ + +long AvailableMemoryArea::find(address_t *start, address_t *size, + map_flags_t flags, unsigned char align, + MemoryArea **area) +{ + /* Obtain the alignment increment and a properly aligned size. */ + + address_t increment = 1UL << align; + address_t region_size = round(*size, increment); + + /* Align any desired location. */ + + address_t region_start = trunc(*start, increment); + + /* Enforce a minimum address. */ + + if (region_start < _start) + region_start = round(_start, increment); + + /* Search for existing regions after the desired, conformant start address. */ + + MemoryAreaMap::iterator it = _areas.upper_bound(region_start); + + /* Consider any area preceding or encompassing the desired address. */ + + if (it != _areas.begin()) + { + MemoryAreaMap::iterator next = it; + + /* Step back to the preceding area to get its details. */ + + it--; + MemoryArea *pr = it->second; + it = next; + + /* Test whether the desired region start is encompassed by the preceding + area. */ + + if (region_start < pr->area_end()) + { + /* Where the preceding area is mapped or a reserved area, adjust the start + of any search range. If an exact request is made for a region, deny the + request. */ + + if (pr->is_mapped() || pr->is_reserved()) + { + if (!(flags & L4RE_RM_F_SEARCH_ADDR)) + return -L4_ENOMEM; + + region_start = round(pr->area_end(), increment); + } + + /* Where the preceding area is an area within which regions might be + established, search within that area. */ + + else + return pr->find(start, size, flags, align, area); + } + } + + /* Consider the regions following the current region start candidate. */ + + MemoryArea *r; + + while ((it != _areas.end()) && !(_end && ((region_start + region_size) > _end))) + { + r = it->second; + + /* Obtain the limit of available space being considered. */ + + address_t end_limit = r->area_start(); + + /* Test if not enough space exists between the preceding region (or start of + memory) and the current region. */ + + if ((region_start + region_size) > end_limit) + { + /* If an exact request is made for a region, deny the request. */ + + if (!(flags & L4RE_RM_F_SEARCH_ADDR)) + return -L4_ENOMEM; + + /* Otherwise, investigate subsequent regions if not enough space exists + between the preceding region (or start of memory) and the current + region. */ + + region_start = round(r->area_end(), increment); + it++; + } + + /* Otherwise, the region can be positioned. */ + + else + break; + } + + /* Test for enough memory constrained by any predefined limit. */ + + if (_end && ((region_start + region_size) > _end)) + return -L4_ENOMEM; + + /* Return the configured start and size. */ + + *start = region_start; + *size = region_size; + + /* Return the area within which any region will be added. */ + + *area = this; + + return L4_EOK; +} + +/* Obtain a recursive iterator over a memory area. */ + +AvailableMemoryArea::iterator AvailableMemoryArea::begin() +{ + return AvailableMemoryArea::iterator(_areas.begin(), _areas.end()); +} + +AvailableMemoryArea::iterator AvailableMemoryArea::end() +{ + return AvailableMemoryArea::iterator(_areas.end(), _areas.end()); +} + +MemoryAreaMap::iterator AvailableMemoryArea::areas_begin() +{ + return _areas.begin(); +} + +MemoryAreaMap::iterator AvailableMemoryArea::areas_end() +{ + return _areas.end(); +} + + + +/* Initialise a recursive iterator over a memory area. */ + +AvailableMemoryArea::iterator::iterator(MemoryAreaMap::iterator it, + MemoryAreaMap::iterator end) +{ + _iterators.push(it); + _ends.push(end); + + /* Descend to the first non-container area. */ + + descend_all(); +} + +AvailableMemoryArea::iterator::iterator() +{ +} + +/* Return the current underlying iterator. */ + +MemoryAreaMap::iterator &AvailableMemoryArea::iterator::area_iterator() +{ + return _iterators.top(); +} + +/* Return the end point of the current underlying iterator. */ + +MemoryAreaMap::iterator &AvailableMemoryArea::iterator::area_end() +{ + return _ends.top(); +} + +/* Return the current area. */ + +MemoryArea *AvailableMemoryArea::iterator::operator *() +{ + return area_iterator()->second; +} + +/* Return whether this iterator references the same area as the other + iterator. */ + +bool AvailableMemoryArea::iterator::operator ==(AvailableMemoryArea::iterator other) +{ + return area_iterator() == other.area_iterator(); +} + +/* Return whether this iterator references a different area to the other + iterator. */ + +bool AvailableMemoryArea::iterator::operator !=(AvailableMemoryArea::iterator other) +{ + return area_iterator() != other.area_iterator(); +} + +/* Advance this iterator to the next area. */ + +AvailableMemoryArea::iterator &AvailableMemoryArea::iterator::operator ++() +{ + /* Advance the area iterator. */ + + area_iterator()++; + + /* Descend to the next non-container area. */ + + descend_all(); + + return *this; +} + +AvailableMemoryArea::iterator &AvailableMemoryArea::iterator::operator ++(int) +{ + return ++(*this); +} + +/* Advance this iterator to the next area not containing other areas. */ + +void AvailableMemoryArea::iterator::descend_all() +{ + while ((area_iterator() != area_end()) || (_iterators.size() > 1)) + { + /* Handle empty areas by ascending to refer to the area. */ + + if (area_iterator() == area_end()) + { + ascend(); + break; + } + + MemoryArea *r = area_iterator()->second; + + /* Handle areas by descending into them. */ + + if (!r->is_reserved() && !r->is_mapped()) + descend(); + + /* Yield any non-container areas. */ + + else + break; + } +} + +/* Ascend from a memory area. */ + +void AvailableMemoryArea::iterator::ascend() +{ + _iterators.pop(); + _ends.pop(); +} + +/* Descend into a memory area. */ + +void AvailableMemoryArea::iterator::descend() +{ + AvailableMemoryArea *a = dynamic_cast(area_iterator()->second); + + if (a != NULL) + { + _iterators.push(a->areas_begin()); + _ends.push(a->areas_end()); + } +} + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r d0e6f1d3f337 -r bae2ddb47ecd libexec/lib/src/pager.cc --- a/libexec/lib/src/pager.cc Tue Mar 14 23:51:57 2023 +0100 +++ b/libexec/lib/src/pager.cc Wed Mar 15 00:33:40 2023 +0100 @@ -20,7 +20,6 @@ */ #include -#include #include @@ -31,7 +30,7 @@ /* Initialise common functionality. */ ExecPager::ExecPager(address_t start, address_t end) -: _start(start), _end(end) +: _area(start, end) { } @@ -43,118 +42,34 @@ -/* Add a region to the pager. */ +/* Add an area to the pager. */ -void ExecPager::add(MappedRegion ®ion) +void ExecPager::add(MemoryArea &area) { - _regions[region.start] = region; + _area.add(area); } -/* Remove a region from the pager. */ +/* Remove an area from the pager. */ -void ExecPager::remove(MappedRegion ®ion) +void ExecPager::remove(MemoryArea &area) { - _regions.erase(region.start); + _area.remove(area); } -/* Attach a region for provision when page faults occur. */ +/* Find an area suitable for attaching a memory region. */ long ExecPager::find(address_t *start, address_t *size, map_flags_t flags, - address_t offset, unsigned char align) + unsigned char align, MemoryArea **area) { if (align < L4_PAGESHIFT) align = L4_PAGESHIFT; - /* Obtain the alignment increment and a properly aligned size. */ - - address_t increment = 1UL << align; - address_t region_size = round(*size, increment); - - /* Either attempt to find an address for the specified region, starting from + /* Attempt to find an address for the specified region, starting from any indicated address. */ - if (flags & L4RE_RM_F_SEARCH_ADDR) - { - /* Align any desired location. */ - - address_t region_start = trunc(*start, increment); - - /* Enforce a minimum address. */ - - if (region_start < _start) - region_start = round(_start, increment); - - /* Search for existing regions after the desired, conformant address. */ - - MappedRegions::iterator it = _regions.upper_bound(region_start); - - /* Consider any region preceding or encompassing the desired address. */ - - if (it != _regions.begin()) - { - MappedRegions::iterator next = it; - - /* Step back to the preceding region to get its details. */ - - it--; - MappedRegion &pr = it->second; - address_t previous_end = pr.start + pr.size; - it = next; - - /* The preceding region may displace the desired region location if it - is encompassed by the region. */ - - if (region_start < previous_end) - region_start = round(previous_end, increment); - } - - /* Consider the regions following the current region start candidate. */ - - while ((it != _regions.end()) && !(_end && ((region_start + region_size) > _end))) - { - MappedRegion &r = it->second; - - /* Obtain the limit of available space being considered. */ - - address_t end_limit = r.start; - - /* Investigate subsequent regions if not enough space exists between the - preceding region (or start of memory) and the current region. */ - - if ((region_start + region_size) > end_limit) - { - region_start = round(r.start + r.size, increment); - it++; - } - - /* Otherwise, the region can be positioned. */ - - else - break; - } - - /* Test for enough memory constrained by any predefined limit. */ - - if (_end && ((region_start + region_size) > _end)) - return -L4_ENOMEM; - - /* Return the configured start and size. */ - - *start = region_start; - *size = region_size; - return L4_EOK; - } - - /* Or attempt to add the specified region at a specific address. */ - - else - { - // NOTE: To be implemented. - - return -L4_ENOMEM; - } + return _area.find(start, size, flags, align, area); } /* vim: tabstop=2 expandtab shiftwidth=2 diff -r d0e6f1d3f337 -r bae2ddb47ecd libexec/lib/src/segment.cc --- a/libexec/lib/src/segment.cc Tue Mar 14 23:51:57 2023 +0100 +++ b/libexec/lib/src/segment.cc Wed Mar 15 00:33:40 2023 +0100 @@ -141,7 +141,8 @@ MappedRegion &Segment::region() { - _region = MappedRegion(_region_base, _region_allocated_size, region_flags(), _ds, (l4_addr_t) _buf); + _region = MappedRegion(_region_base, _region_base + _region_allocated_size, + region_flags(), _ds, (l4_addr_t) _buf); return _region; } diff -r d0e6f1d3f337 -r bae2ddb47ecd libexec/rm/region_mapper.cc --- a/libexec/rm/region_mapper.cc Tue Mar 14 23:51:57 2023 +0100 +++ b/libexec/rm/region_mapper.cc Wed Mar 15 00:33:40 2023 +0100 @@ -57,8 +57,8 @@ for (; region && (region->ds != L4_INVALID_CAP); region++) { - printf("Adding region: {%lx, %llx, %lx, %lx}\n", region->start, region->size, region->flags, region->ds); - MappedRegion r(region->start, region->size, region->flags, region->ds); + printf("Adding region: {%lx, %llx, %lx, %lx}\n", region->start, region->start + region->size, region->flags, region->ds); + MappedRegion r(region->start, region->start + region->size, region->flags, region->ds); exec_pager.add(r); }