1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/libexec/lib/src/external_pager.cc Sun Jun 12 18:56:25 2022 +0200
1.3 @@ -0,0 +1,257 @@
1.4 +/*
1.5 + * A system pager implementation residing in a separate task.
1.6 + *
1.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU General Public License as
1.11 + * published by the Free Software Foundation; either version 2 of
1.12 + * the License, or (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 + * Boston, MA 02110-1301, USA
1.23 + */
1.24 +
1.25 +#include <l4/re/env.h>
1.26 +#include <l4/sys/err.h>
1.27 +#include <l4/util/util.h>
1.28 +
1.29 +#include <ipc/mem_ipc.h>
1.30 +#include <mem/memory_utils.h>
1.31 +
1.32 +#include <stdio.h>
1.33 +#include <string.h>
1.34 +
1.35 +#include "external_pager.h"
1.36 +
1.37 +
1.38 +
1.39 +/* A simple system pager also acting as a region mapper. */
1.40 +
1.41 +/* Add a region to the pager. */
1.42 +
1.43 +void ExternalPager::add(MappedRegion ®ion)
1.44 +{
1.45 + _regions[region.map_start] = region;
1.46 +}
1.47 +
1.48 +/* Handle a general exception. */
1.49 +
1.50 +long ExternalPager::exception(l4_exc_regs_t regs, l4_snd_fpage_t *region)
1.51 +{
1.52 + (void) region;
1.53 +
1.54 + printf("exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(®s), l4_utcb_exc_pc(®s));
1.55 +
1.56 + printf("r15 = %lx\n", regs.r15);
1.57 + printf("r14 = %lx\n", regs.r14);
1.58 + printf("r13 = %lx\n", regs.r13);
1.59 + printf("r12 = %lx\n", regs.r12);
1.60 + printf("r11 = %lx\n", regs.r11);
1.61 + printf("r10 = %lx\n", regs.r10);
1.62 + printf("r9 = %lx\n", regs.r9);
1.63 + printf("r8 = %lx\n", regs.r8);
1.64 + printf("rdi = %lx\n", regs.rdi);
1.65 + printf("rsi = %lx\n", regs.rsi);
1.66 + printf("rbp = %lx\n", regs.rbp);
1.67 + printf("pfa = %lx\n", regs.pfa);
1.68 + printf("rbx = %lx\n", regs.rbx);
1.69 + printf("rdx = %lx\n", regs.rdx);
1.70 + printf("rcx = %lx\n", regs.rcx);
1.71 + printf("rax = %lx\n", regs.rax);
1.72 + printf("trapno = %lx\n", regs.trapno);
1.73 + printf("err = %lx\n", regs.err);
1.74 + printf("ip = %lx\n", regs.ip);
1.75 + printf("flags = %lx\n", regs.flags);
1.76 + printf("sp = %lx\n", regs.sp);
1.77 + printf("ss = %lx\n", regs.ss);
1.78 + printf("fs_base = %lx\n", regs.fs_base);
1.79 + printf("gs_base = %lx\n", regs.gs_base);
1.80 +
1.81 + return L4_EOK;
1.82 +}
1.83 +
1.84 +#define DEBUG 0
1.85 +
1.86 +/* Handle a page fault using any configured regions. */
1.87 +
1.88 +long ExternalPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region)
1.89 +{
1.90 + l4_umword_t addr = pfa & ~7UL, flags = pfa & 7;
1.91 +
1.92 +#if DEBUG
1.93 + printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags);
1.94 +#endif
1.95 +
1.96 + MappedRegions::iterator it = _regions.upper_bound(addr);
1.97 +
1.98 + if (it != _regions.begin())
1.99 + it--;
1.100 + else
1.101 + {
1.102 + printf("not mapped!\n");
1.103 + return -L4_ENOMEM;
1.104 + }
1.105 +
1.106 + MappedRegion &r = it->second;
1.107 +
1.108 + if ((addr >= r.map_start) && (addr < r.map_start + r.size))
1.109 + {
1.110 + l4_addr_t page_addr = trunc(addr, L4_PAGESIZE);
1.111 +
1.112 + region->fpage = l4_fpage(r.start + (page_addr - r.map_start), L4_PAGESHIFT, r.flags);
1.113 + region->snd_base = page_addr;
1.114 +
1.115 +#if DEBUG
1.116 + printf("%lx...%lx from %lx...%lx offset %lx size %d rights %x\n",
1.117 + r.map_start, region->snd_base,
1.118 + r.start, l4_fpage_memaddr(region->fpage),
1.119 + addr - r.map_start,
1.120 + l4_fpage_size(region->fpage),
1.121 + l4_fpage_rights(region->fpage));
1.122 +
1.123 + printf("%lx -> ", addr);
1.124 +
1.125 + for (unsigned int i = 0; i < sizeof(l4_umword_t); i++)
1.126 + printf("%02x", *((unsigned char *)(r.start + (addr - r.map_start) + i)));
1.127 +
1.128 + printf("\n");
1.129 +#endif
1.130 +
1.131 + if (r.flags & L4RE_RM_F_W)
1.132 + l4_touch_rw((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE);
1.133 + else
1.134 + l4_touch_ro((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE);
1.135 +
1.136 + return L4_EOK;
1.137 + }
1.138 +
1.139 +#if DEBUG
1.140 + printf("not mapped!\n");
1.141 +#endif
1.142 +
1.143 + return -L4_ENOMEM;
1.144 +}
1.145 +
1.146 +/* Attach a region for provision when page faults occur. This is required in
1.147 + the initialisation of a program by the C library which requires a region
1.148 + mapper. */
1.149 +
1.150 +long ExternalPager::attach(address_t *start, offset_t size, map_flags_t flags,
1.151 + l4_cap_idx_t ds, address_t offset,
1.152 + unsigned char align)
1.153 +{
1.154 +#if DEBUG
1.155 + printf("attach(%lx, %ld, %lx, ..., %lx, %d)\n", *start, size, flags, offset, align);
1.156 +#endif
1.157 +
1.158 + if (align < L4_PAGESHIFT)
1.159 + align = L4_PAGESHIFT;
1.160 +
1.161 + offset_t increment = 1UL << align;
1.162 + offset_t region_size = round(size, increment);
1.163 +
1.164 + /* Either attempt to find an address for the specified region, starting from
1.165 + any indicated address. */
1.166 +
1.167 + if (flags & L4RE_RM_F_SEARCH_ADDR)
1.168 + {
1.169 + address_t region_start = trunc(*start, increment);
1.170 + MappedRegions::iterator it = _regions.upper_bound(*start);
1.171 +
1.172 + if (!region_start)
1.173 + region_start += increment;
1.174 +
1.175 +#if DEBUG
1.176 + printf("-> search from %lx -> %lx...\n", *start, region_start);
1.177 +#endif
1.178 +
1.179 + /* Before last known region. */
1.180 +
1.181 + while (it != _regions.end())
1.182 + {
1.183 + MappedRegions::iterator next = it;
1.184 + MappedRegion &r = it->second;
1.185 + address_t start_limit;
1.186 + address_t end_limit = r.map_start;
1.187 +
1.188 + /* Consider any preceding region. If no such region exists, choose an
1.189 + address at the start of memory. */
1.190 +
1.191 + if (it == _regions.begin())
1.192 + start_limit = L4_PAGESIZE;
1.193 + else
1.194 + {
1.195 + it--;
1.196 + MappedRegion &pr = it->second;
1.197 + start_limit = pr.map_start + pr.size;
1.198 + it = next;
1.199 + }
1.200 +
1.201 + /* Test against the limits. */
1.202 +
1.203 + if (region_start < start_limit)
1.204 + region_start = round(start_limit, increment);
1.205 +
1.206 + /* Investigate subsequent regions if not enough space exists between the
1.207 + preceding region (or start of memory) and the current region. */
1.208 +
1.209 + if ((region_start + region_size) > end_limit)
1.210 + {
1.211 + it++;
1.212 + if (it == _regions.end())
1.213 + return -L4_ENOMEM;
1.214 + }
1.215 + else
1.216 + break;
1.217 + }
1.218 +
1.219 + /* Attach the provided dataspace.
1.220 + NOTE: This is only done in this implementation to support the paging
1.221 + mechanism. In a region mapper residing within the actual task, the
1.222 + dataspace's map operation would be invoked to obtain mappings. */
1.223 +
1.224 + l4_addr_t ds_start;
1.225 +
1.226 + long err = ipc_attach_dataspace(ds, size, (void **) &ds_start);
1.227 +
1.228 + if (err)
1.229 + return err;
1.230 +
1.231 + l4_touch_rw((const void *) ds_start, size);
1.232 +
1.233 +#if DEBUG
1.234 + printf("-> added region for %lx size %ld (%d)\n", region_start, region_size, page_order(region_size));
1.235 +#endif
1.236 +
1.237 + MappedRegion r(ds_start, region_size, flags & L4RE_DS_F_RIGHTS_MASK, region_start);
1.238 +
1.239 + add(r);
1.240 +
1.241 + *start = region_start;
1.242 + return L4_EOK;
1.243 + }
1.244 +
1.245 + /* Or attempt to add the specified region at a specific address. */
1.246 +
1.247 + else
1.248 + {
1.249 + // NOTE: To be implemented.
1.250 +
1.251 +#if DEBUG
1.252 + printf("-> region of size %ld (%d) not added!\n", region_size, page_order(region_size));
1.253 +#endif
1.254 +
1.255 + return -L4_ENOMEM;
1.256 + }
1.257 +}
1.258 +
1.259 +/* vim: tabstop=2 expandtab shiftwidth=2
1.260 +*/