# HG changeset patch # User Paul Boddie # Date 1664636296 -7200 # Node ID 2ecda157686f026bdef962894b41d529bc8032c3 # Parent a1b2f63d60b0b219d1fe3f9d2233310be9186efa Fixed region allocation conflicts when running programs by reserving different memory areas for the different region mappers. Consolidated region mapper functionality in the parent ExecPager class, fixing various aspects of the region positioning behaviour and introducing support for limitations on the memory area available for regions. diff -r a1b2f63d60b0 -r 2ecda157686f libexec/include/exec/external_pager.h --- a/libexec/include/exec/external_pager.h Sat Oct 01 16:53:23 2022 +0200 +++ b/libexec/include/exec/external_pager.h Sat Oct 01 16:58:16 2022 +0200 @@ -21,28 +21,16 @@ #pragma once -#include - -#include #include -/* Collection types. */ - -typedef std::map MappedRegions; - - - /* A simple system pager also acting as a region mapper. */ class ExternalPager : public ExecPager { -protected: - MappedRegions _regions; - public: - virtual void add(MappedRegion ®ion); + explicit ExternalPager(address_t start = 0, address_t end = 0); /* Notification methods, implementing PagerObject. */ @@ -56,7 +44,6 @@ virtual long attach(address_t *start, address_t size, map_flags_t flags, l4_cap_idx_t ds, address_t offset, unsigned char align); - }; /* vim: tabstop=2 expandtab shiftwidth=2 diff -r a1b2f63d60b0 -r 2ecda157686f libexec/include/exec/internal_pager.h --- a/libexec/include/exec/internal_pager.h Sat Oct 01 16:53:23 2022 +0200 +++ b/libexec/include/exec/internal_pager.h Sat Oct 01 16:58:16 2022 +0200 @@ -21,29 +21,16 @@ #pragma once -#include - -#include #include -/* Collection types. */ - -typedef std::map ExecRegions; -typedef struct exec_region ExecRegion; - - - /* A simple system pager also acting as a region mapper. */ class InternalPager : public ExecPager { -protected: - ExecRegions _regions; - public: - virtual void add(ExecRegion ®ion); + explicit InternalPager(address_t start = 0, address_t end = 0); /* Notification methods, implementing PagerObject. */ @@ -57,7 +44,6 @@ virtual long attach(address_t *start, address_t size, map_flags_t flags, l4_cap_idx_t ds, address_t offset, unsigned char align); - }; /* vim: tabstop=2 expandtab shiftwidth=2 diff -r a1b2f63d60b0 -r 2ecda157686f libexec/include/exec/mapped_region.h --- a/libexec/include/exec/mapped_region.h Sat Oct 01 16:53:23 2022 +0200 +++ b/libexec/include/exec/mapped_region.h Sat Oct 01 16:58:16 2022 +0200 @@ -35,18 +35,18 @@ l4_addr_t start; offset_t size; l4_umword_t flags; - l4_addr_t map_start; l4_cap_idx_t ds; + l4_addr_t ds_start; explicit MappedRegion() - : start(0), size(0), flags(0), map_start(0), ds(L4_INVALID_CAP) + : start(0), size(0), flags(0), ds(L4_INVALID_CAP), ds_start(0) { } explicit MappedRegion(l4_addr_t start, l4_addr_t size, - l4_umword_t flags, l4_addr_t map_start, - l4_cap_idx_t ds = L4_INVALID_CAP) - : start(start), size(size), flags(flags), map_start(map_start), ds(ds) + 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) { } }; diff -r a1b2f63d60b0 -r 2ecda157686f libexec/include/exec/pager.h --- a/libexec/include/exec/pager.h Sat Oct 01 16:53:23 2022 +0200 +++ b/libexec/include/exec/pager.h Sat Oct 01 16:58:16 2022 +0200 @@ -1,5 +1,5 @@ /* - * A system pager interface. + * Common system pager functionality. * * Copyright (C) 2022 Paul Boddie * @@ -21,30 +21,48 @@ #pragma once +#include + +#include + #include "pager_object_interface.h" +/* Collection types. */ + +typedef std::map MappedRegions; + + + /* A simple system pager also acting as a region mapper. */ class ExecPager : public PagerObject { +protected: + address_t _start, _end; + + /* 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); + public: + explicit ExecPager(address_t start = 0, address_t end = 0); + virtual ~ExecPager(); + virtual void add(MappedRegion ®ion); + /* Notification methods. */ virtual long exception(l4_exc_regs_t regs, l4_snd_fpage_t *region) = 0; virtual long page_fault(l4_umword_t pfa, l4_umword_t pc, - l4_snd_fpage_t *region); - - /* Region manager/mapper methods. */ - - virtual long attach(address_t *start, address_t size, map_flags_t flags, - l4_cap_idx_t ds, address_t offset, unsigned char align); - + l4_snd_fpage_t *region) = 0; }; /* vim: tabstop=2 expandtab shiftwidth=2 diff -r a1b2f63d60b0 -r 2ecda157686f libexec/lib/src/external_pager.cc --- a/libexec/lib/src/external_pager.cc Sat Oct 01 16:53:23 2022 +0200 +++ b/libexec/lib/src/external_pager.cc Sat Oct 01 16:58:16 2022 +0200 @@ -20,26 +20,26 @@ */ #include -#include #include #include #include #include -#include #include "external_pager.h" +#define DEBUG 0 + + + /* A simple system pager also acting as a region mapper. */ -/* Add a region to the pager. */ - -void ExternalPager::add(MappedRegion ®ion) +ExternalPager::ExternalPager(address_t start, address_t end) +: ExecPager(start, end) { - _regions[region.map_start] = region; } /* Handle a general exception. */ @@ -48,43 +48,16 @@ { (void) region; - printf("exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(®s), l4_utcb_exc_pc(®s)); + printf("ExternalPager::exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(®s), l4_utcb_exc_pc(®s)); -#if 0 - printf("r15 = %lx\n", regs.r15); - printf("r14 = %lx\n", regs.r14); - printf("r13 = %lx\n", regs.r13); - printf("r12 = %lx\n", regs.r12); - printf("r11 = %lx\n", regs.r11); - printf("r10 = %lx\n", regs.r10); - printf("r9 = %lx\n", regs.r9); - printf("r8 = %lx\n", regs.r8); - printf("rdi = %lx\n", regs.rdi); - printf("rsi = %lx\n", regs.rsi); - printf("rbp = %lx\n", regs.rbp); - printf("pfa = %lx\n", regs.pfa); - printf("rbx = %lx\n", regs.rbx); - printf("rdx = %lx\n", regs.rdx); - printf("rcx = %lx\n", regs.rcx); - printf("rax = %lx\n", regs.rax); - printf("trapno = %lx\n", regs.trapno); - printf("err = %lx\n", regs.err); - printf("ip = %lx\n", regs.ip); - printf("flags = %lx\n", regs.flags); - printf("sp = %lx\n", regs.sp); - printf("ss = %lx\n", regs.ss); - printf("fs_base = %lx\n", regs.fs_base); - printf("gs_base = %lx\n", regs.gs_base); -#endif - +#if DEBUG while (1) l4_sleep_forever(); +#endif return L4_EOK; } -#define DEBUG 0 - /* Handle a page fault using any configured regions. */ long ExternalPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region) @@ -101,13 +74,13 @@ it--; else { - printf("not mapped!\n"); + printf("not mapped at %lx for pc %lx\n", addr, pc); return -L4_ENOMEM; } MappedRegion &r = it->second; - if ((addr >= r.map_start) && (addr < r.map_start + r.size)) + if ((addr >= r.start) && (addr < r.start + r.size)) { l4_addr_t page_addr = trunc(addr, L4_PAGESIZE); map_flags_t map_flags = (flags & 4 ? L4RE_DS_F_RX : 0) | (flags & 2 ? L4RE_DS_F_W : 0) | (flags & 1 ? L4RE_DS_F_R : 0); @@ -115,14 +88,14 @@ if (!map_flags) map_flags = L4RE_DS_F_R; - region->fpage = l4_fpage(r.start + (page_addr - r.map_start), L4_PAGESHIFT, map_flags & r.flags); + region->fpage = l4_fpage(r.ds_start + (page_addr - r.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.map_start, region->snd_base, - r.start, l4_fpage_memaddr(region->fpage), - addr - r.map_start, + r.start, region->snd_base, + r.ds_start, l4_fpage_memaddr(region->fpage), + addr - r.start, l4_fpage_size(region->fpage), l4_fpage_rights(region->fpage), r.ds); @@ -130,15 +103,15 @@ printf("%lx -> ", addr); for (unsigned int i = 0; i < sizeof(l4_umword_t); i++) - printf("%02x", *((unsigned char *)(r.start + (addr - r.map_start) + i))); + printf("%02x", *((unsigned char *)(r.ds_start + (addr - r.start) + i))); printf("\n"); #endif if (r.flags & L4RE_RM_F_W) - l4_touch_rw((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE); + l4_touch_rw((const void *) (r.ds_start + (page_addr - r.start)), L4_PAGESIZE); else - l4_touch_ro((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE); + l4_touch_ro((const void *) (r.ds_start + (page_addr - r.start)), L4_PAGESIZE); return L4_EOK; } @@ -158,109 +131,28 @@ l4_cap_idx_t ds, address_t offset, unsigned char align) { -#if DEBUG - printf("attach(%lx, %ld, %lx, ..., %lx, %d)\n", *start, size, flags, offset, align); -#endif - - if (align < L4_PAGESHIFT) - align = L4_PAGESHIFT; - - address_t increment = 1UL << align; - address_t region_size = round(size, increment); - - /* Either attempt to find an address for the specified region, starting from - any indicated address. */ - - if (flags & L4RE_RM_F_SEARCH_ADDR) - { - address_t region_start = trunc(*start, increment); - MappedRegions::iterator it = _regions.upper_bound(*start); - - if (!region_start) - region_start += increment; - -#if DEBUG - printf("-> search from %lx -> %lx...\n", *start, region_start); -#endif - - /* Before last known region. */ + long err = find(start, &size, flags, offset, align); - while (it != _regions.end()) - { - MappedRegions::iterator next = it; - MappedRegion &r = it->second; - address_t start_limit; - address_t end_limit = r.map_start; - - /* Consider any preceding region. If no such region exists, choose an - address at the start of memory. */ - - if (it == _regions.begin()) - start_limit = L4_PAGESIZE; - else - { - it--; - MappedRegion &pr = it->second; - start_limit = pr.map_start + pr.size; - it = next; - } - - /* Test against the limits. */ - - if (region_start < start_limit) - region_start = round(start_limit, increment); - - /* 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) - { - it++; - if (it == _regions.end()) - return -L4_ENOMEM; - } - else - break; - } - + if (!err) + { /* Attach the provided dataspace. NOTE: This is only done in this implementation to support the paging mechanism. In a region mapper residing within the actual task, the dataspace's map operation would be invoked to obtain mappings. */ l4_addr_t ds_start; - - long err = ipc_attach_dataspace(ds, size, (void **) &ds_start); + err = ipc_attach_dataspace(ds, size, (void **) &ds_start); if (err) return err; l4_touch_rw((const void *) ds_start, size); -#if DEBUG - printf("-> added region at %lx size %ld (%d) from %lx ds %lx\n", region_start, region_size, page_order(region_size), ds_start, ds); -#endif - - MappedRegion r(ds_start, region_size, flags & L4RE_DS_F_RIGHTS_MASK, region_start, ds); - + MappedRegion r(*start, size, flags & L4RE_DS_F_RIGHTS_MASK, ds, ds_start); add(r); - - *start = region_start; - return L4_EOK; } - /* Or attempt to add the specified region at a specific address. */ - - else - { - // NOTE: To be implemented. - -#if DEBUG - printf("-> region of size %ld (%d) not added!\n", region_size, page_order(region_size)); -#endif - - return -L4_ENOMEM; - } + return err; } /* vim: tabstop=2 expandtab shiftwidth=2 diff -r a1b2f63d60b0 -r 2ecda157686f libexec/lib/src/internal_pager.cc --- a/libexec/lib/src/internal_pager.cc Sat Oct 01 16:53:23 2022 +0200 +++ b/libexec/lib/src/internal_pager.cc Sat Oct 01 16:58:16 2022 +0200 @@ -20,27 +20,26 @@ */ #include -#include -#include +#include -#include #include #include -#include #include "dataspace_client.h" #include "internal_pager.h" +#define DEBUG 0 + + + /* A simple system pager also acting as a region mapper. */ -/* Add a region to the pager. */ - -void InternalPager::add(ExecRegion ®ion) +InternalPager::InternalPager(address_t start, address_t end) +: ExecPager(start, end) { - _regions[region.start] = region; } /* Handle a general exception. */ @@ -49,43 +48,16 @@ { (void) region; - printf("exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(®s), l4_utcb_exc_pc(®s)); + printf("InternalPager::exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(®s), l4_utcb_exc_pc(®s)); -#if 0 - printf("r15 = %lx\n", regs.r15); - printf("r14 = %lx\n", regs.r14); - printf("r13 = %lx\n", regs.r13); - printf("r12 = %lx\n", regs.r12); - printf("r11 = %lx\n", regs.r11); - printf("r10 = %lx\n", regs.r10); - printf("r9 = %lx\n", regs.r9); - printf("r8 = %lx\n", regs.r8); - printf("rdi = %lx\n", regs.rdi); - printf("rsi = %lx\n", regs.rsi); - printf("rbp = %lx\n", regs.rbp); - printf("pfa = %lx\n", regs.pfa); - printf("rbx = %lx\n", regs.rbx); - printf("rdx = %lx\n", regs.rdx); - printf("rcx = %lx\n", regs.rcx); - printf("rax = %lx\n", regs.rax); - printf("trapno = %lx\n", regs.trapno); - printf("err = %lx\n", regs.err); - printf("ip = %lx\n", regs.ip); - printf("flags = %lx\n", regs.flags); - printf("sp = %lx\n", regs.sp); - printf("ss = %lx\n", regs.ss); - printf("fs_base = %lx\n", regs.fs_base); - printf("gs_base = %lx\n", regs.gs_base); -#endif - +#if DEBUG while (1) l4_sleep_forever(); +#endif return L4_EOK; } -#define DEBUG 0 - /* Handle a page fault using any configured regions. */ long InternalPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region) @@ -94,19 +66,21 @@ #if DEBUG printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags); + l4_thread_regs_t *regs = l4_utcb_tcr(); + printf("regs = %p\n; regs->user[0] = %lx\n", regs, regs->user[0]); #endif - ExecRegions::iterator it = _regions.upper_bound(addr); + MappedRegions::iterator it = _regions.upper_bound(addr); if (it != _regions.begin()) it--; else { - printf("not mapped!\n"); + printf("not mapped at %lx for pc %lx\n", addr, pc); return -L4_ENOMEM; } - ExecRegion &r = it->second; + MappedRegion &r = it->second; if ((addr >= r.start) && (addr < r.start + r.size)) { @@ -157,95 +131,15 @@ l4_cap_idx_t ds, address_t offset, unsigned char align) { -#if DEBUG - printf("attach(%lx, %ld, %lx, ..., %lx, %d)\n", *start, size, flags, offset, align); -#endif - - if (align < L4_PAGESHIFT) - align = L4_PAGESHIFT; - - address_t increment = 1UL << align; - address_t region_size = round(size, increment); - - /* Either attempt to find an address for the specified region, starting from - any indicated address. */ - - if (flags & L4RE_RM_F_SEARCH_ADDR) - { - address_t region_start = trunc(*start, increment); - ExecRegions::iterator it = _regions.upper_bound(*start); - - if (!region_start) - region_start += increment; - -#if DEBUG - printf("-> search from %lx -> %lx...\n", *start, region_start); -#endif - - /* Before last known region. */ - - while (it != _regions.end()) - { - ExecRegions::iterator next = it; - ExecRegion &r = it->second; - address_t start_limit; - address_t end_limit = r.start; - - /* Consider any preceding region. If no such region exists, choose an - address at the start of memory. */ + long err = find(start, &size, flags, offset, align); - if (it == _regions.begin()) - start_limit = L4_PAGESIZE; - else - { - it--; - ExecRegion &pr = it->second; - start_limit = pr.start + pr.size; - it = next; - } - - /* Test against the limits. */ - - if (region_start < start_limit) - region_start = round(start_limit, increment); - - /* 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) - { - it++; - if (it == _regions.end()) - return -L4_ENOMEM; - } - else - break; - } - -#if DEBUG - printf("-> added region at %lx size %ld (%d) ds %lx\n", region_start, region_size, page_order(region_size), ds); -#endif - - ExecRegion r = (ExecRegion) {region_start, region_size, flags & L4RE_DS_F_RIGHTS_MASK, ds}; - + if (!err) + { + MappedRegion r(*start, size, flags & L4RE_DS_F_RIGHTS_MASK, ds); add(r); - - *start = region_start; - return L4_EOK; } - /* Or attempt to add the specified region at a specific address. */ - - else - { - // NOTE: To be implemented. - -#if DEBUG - printf("-> region of size %ld (%d) not added!\n", region_size, page_order(region_size)); -#endif - - return -L4_ENOMEM; - } + return err; } /* vim: tabstop=2 expandtab shiftwidth=2 diff -r a1b2f63d60b0 -r 2ecda157686f libexec/lib/src/pager.cc --- a/libexec/lib/src/pager.cc Sat Oct 01 16:53:23 2022 +0200 +++ b/libexec/lib/src/pager.cc Sat Oct 01 16:58:16 2022 +0200 @@ -1,5 +1,5 @@ /* - * A system pager interface. + * Common system pager functionality. * * Copyright (C) 2022 Paul Boddie * @@ -19,15 +19,132 @@ * Boston, MA 02110-1301, USA */ +#include +#include + +#include + #include "pager.h" +/* Initialise common functionality. */ + +ExecPager::ExecPager(address_t start, address_t end) +: _start(start), _end(end) +{ +} + /* Necessary virtual destructor. */ ExecPager::~ExecPager() { } +/* Add a region to the pager. */ + +void ExecPager::add(MappedRegion ®ion) +{ + _regions[region.start] = region; +} + +/* Attach a region for provision when page faults occur. */ + +long ExecPager::find(address_t *start, address_t *size, map_flags_t flags, + address_t offset, unsigned char align) +{ + 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 + 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; + } +} + /* vim: tabstop=2 expandtab shiftwidth=2 */ diff -r a1b2f63d60b0 -r 2ecda157686f libexec/lib/src/segment.cc --- a/libexec/lib/src/segment.cc Sat Oct 01 16:53:23 2022 +0200 +++ b/libexec/lib/src/segment.cc Sat Oct 01 16:58:16 2022 +0200 @@ -121,7 +121,7 @@ MappedRegion &Segment::region() { - _region = MappedRegion((l4_addr_t) _buf, _region_allocated_size, region_flags(), _region_base, _ds); + _region = MappedRegion(_region_base, _region_allocated_size, region_flags(), _ds, (l4_addr_t) _buf); return _region; } diff -r a1b2f63d60b0 -r 2ecda157686f libexec/rm/region_mapper.cc --- a/libexec/rm/region_mapper.cc Sat Oct 01 16:53:23 2022 +0200 +++ b/libexec/rm/region_mapper.cc Sat Oct 01 16:58:16 2022 +0200 @@ -30,7 +30,10 @@ -static InternalPager exec_pager; +/* Initialise a pager for programs, reserving space below the allocated regions + for the region mapper itself. */ + +static InternalPager exec_pager(L4_PAGESIZE * 10); @@ -56,7 +59,8 @@ for (; region && (region->ds != L4_INVALID_CAP); region++) { printf("Adding region: {%lx, %lx, %lx, %lx}\n", region->start, region->size, region->flags, region->ds); - exec_pager.add(*region); + MappedRegion r(region->start, region->size, region->flags, region->ds); + exec_pager.add(r); } /* Start the pager. */ diff -r a1b2f63d60b0 -r 2ecda157686f tests/dstest_exec.cc --- a/tests/dstest_exec.cc Sat Oct 01 16:53:23 2022 +0200 +++ b/tests/dstest_exec.cc Sat Oct 01 16:58:16 2022 +0200 @@ -40,9 +40,12 @@ -/* External system-level pager for the region mapper in a created task. */ +/* External system-level pager for the region mapper in a created task. The + allocated regions requested by the region mapper are constrained to an area + of memory that must not overlap with the area reserved for the program being + run. */ -static ExternalPager exec_pager; +static ExternalPager exec_pager(0, 10 * L4_PAGESIZE); static const offset_t initial_stack_size = 16 * L4_PAGESIZE;