1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/libexec/lib/src/pager.cc Mon Jun 06 01:02:59 2022 +0200
1.3 @@ -0,0 +1,255 @@
1.4 +/*
1.5 + * A system pager implementation.
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 "pager.h"
1.36 +#include "pager_object_server.h"
1.37 +
1.38 +
1.39 +
1.40 +/* A simple system pager also acting as a region mapper. */
1.41 +
1.42 +/* Add a region to the pager. */
1.43 +
1.44 +void ExecPager::add(MappedRegion region)
1.45 +{
1.46 + _regions[region.map_start] = region;
1.47 +}
1.48 +
1.49 +/* Handle a general exception. */
1.50 +
1.51 +long ExecPager::exception(l4_exc_regs_t regs, l4_snd_fpage_t *region)
1.52 +{
1.53 + (void) region;
1.54 +
1.55 + printf("exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(®s), l4_utcb_exc_pc(®s));
1.56 +
1.57 + printf("r15 = %lx\n", regs.r15);
1.58 + printf("r14 = %lx\n", regs.r14);
1.59 + printf("r13 = %lx\n", regs.r13);
1.60 + printf("r12 = %lx\n", regs.r12);
1.61 + printf("r11 = %lx\n", regs.r11);
1.62 + printf("r10 = %lx\n", regs.r10);
1.63 + printf("r9 = %lx\n", regs.r9);
1.64 + printf("r8 = %lx\n", regs.r8);
1.65 + printf("rdi = %lx\n", regs.rdi);
1.66 + printf("rsi = %lx\n", regs.rsi);
1.67 + printf("rbp = %lx\n", regs.rbp);
1.68 + printf("pfa = %lx\n", regs.pfa);
1.69 + printf("rbx = %lx\n", regs.rbx);
1.70 + printf("rdx = %lx\n", regs.rdx);
1.71 + printf("rcx = %lx\n", regs.rcx);
1.72 + printf("rax = %lx\n", regs.rax);
1.73 + printf("trapno = %lx\n", regs.trapno);
1.74 + printf("err = %lx\n", regs.err);
1.75 + printf("ip = %lx\n", regs.ip);
1.76 + printf("flags = %lx\n", regs.flags);
1.77 + printf("sp = %lx\n", regs.sp);
1.78 + printf("ss = %lx\n", regs.ss);
1.79 + printf("fs_base = %lx\n", regs.fs_base);
1.80 + printf("gs_base = %lx\n", regs.gs_base);
1.81 +
1.82 + return L4_EOK;
1.83 +}
1.84 +
1.85 +#define DEBUG 0
1.86 +
1.87 +/* Handle a page fault using any configured regions. */
1.88 +
1.89 +long ExecPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region)
1.90 +{
1.91 + l4_umword_t addr = pfa & ~7UL, flags = pfa & 7;
1.92 +
1.93 +#if DEBUG
1.94 + printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags);
1.95 +#endif
1.96 +
1.97 + MappedRegions::iterator it = _regions.upper_bound(addr);
1.98 +
1.99 + if (it != _regions.begin())
1.100 + it--;
1.101 + else
1.102 + {
1.103 + printf("not mapped!\n");
1.104 + return -L4_ENOMEM;
1.105 + }
1.106 +
1.107 + MappedRegion &r = it->second;
1.108 +
1.109 + if ((addr >= r.map_start) && (addr < r.map_start + r.size))
1.110 + {
1.111 + l4_addr_t page_addr = trunc(addr, L4_PAGESIZE);
1.112 +
1.113 + region->fpage = l4_fpage(r.start + (page_addr - r.map_start), L4_PAGESHIFT, r.flags);
1.114 + region->snd_base = page_addr;
1.115 +
1.116 +#if DEBUG
1.117 + printf("%lx...%lx from %lx...%lx offset %lx size %d rights %x\n",
1.118 + r.map_start, region->snd_base,
1.119 + r.start, l4_fpage_memaddr(region->fpage),
1.120 + addr - r.map_start,
1.121 + l4_fpage_size(region->fpage),
1.122 + l4_fpage_rights(region->fpage));
1.123 +
1.124 + printf("%lx -> ", addr);
1.125 +
1.126 + for (unsigned int i = 0; i < sizeof(l4_umword_t); i++)
1.127 + printf("%02x", *((unsigned char *)(r.start + (addr - r.map_start) + i)));
1.128 +
1.129 + printf("\n");
1.130 +#endif
1.131 +
1.132 + if (r.flags & L4RE_RM_F_W)
1.133 + l4_touch_rw((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE);
1.134 + else
1.135 + l4_touch_ro((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE);
1.136 +
1.137 + return L4_EOK;
1.138 + }
1.139 +
1.140 +#if DEBUG
1.141 + printf("not mapped!\n");
1.142 +#endif
1.143 +
1.144 + return -L4_ENOMEM;
1.145 +}
1.146 +
1.147 +/* Attach a region for provision when page faults occur. This is required in
1.148 + the initialisation of a program by the C library which requires a region
1.149 + mapper. */
1.150 +
1.151 +long ExecPager::attach(address_t *start, offset_t size, map_flags_t flags,
1.152 + l4_cap_idx_t ds, address_t offset, 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 + add(MappedRegion(ds_start, region_size, flags & L4RE_DS_F_RIGHTS_MASK, region_start));
1.238 +
1.239 + *start = region_start;
1.240 + return L4_EOK;
1.241 + }
1.242 +
1.243 + /* Or attempt to add the specified region at a specific address. */
1.244 +
1.245 + else
1.246 + {
1.247 + // NOTE: To be implemented.
1.248 +
1.249 +#if DEBUG
1.250 + printf("-> region of size %ld (%d) not added!\n", region_size, page_order(region_size));
1.251 +#endif
1.252 +
1.253 + return -L4_ENOMEM;
1.254 + }
1.255 +}
1.256 +
1.257 +/* vim: tabstop=2 expandtab shiftwidth=2
1.258 +*/