# HG changeset patch # User Paul Boddie # Date 1654470179 -7200 # Node ID 2b7f6a88332e35c041c9d36e0e694af548af34a1 # Parent e54ba46787b6bd6b11b0179667a05531be34dbb0 Moved the system pager implementation to libexec for further work. diff -r e54ba46787b6 -r 2b7f6a88332e libexec/include/exec/pager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/include/exec/pager.h Mon Jun 06 01:02:59 2022 +0200 @@ -0,0 +1,64 @@ +/* + * A system pager implementation. + * + * Copyright (C) 2022 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 "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: + MappedRegions _regions; + +public: + virtual void add(MappedRegion region); + + /* Notification methods. */ + + virtual long exception(l4_exc_regs_t regs, + l4_snd_fpage_t *region); + + 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, offset_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 e54ba46787b6 -r 2b7f6a88332e libexec/lib/src/Makefile --- a/libexec/lib/src/Makefile Mon Jun 06 00:36:14 2022 +0200 +++ b/libexec/lib/src/Makefile Mon Jun 06 01:02:59 2022 +0200 @@ -3,10 +3,55 @@ TARGET = libexec.a libexec.so PC_FILENAME = libexec -SRC_CC = elf.cc memory.cc process.cc segment.cc stack.cc -REQUIRES_LIBS = l4re_c-util libmem libipc libstdc++ libsystypes libfsclient + +# Locations for interface input and generated output. + +IDL_DIR = $(PKGDIR)/../libsystypes/idl +IDL_MK_DIR = $(L4DIR)/idl4re/mk +IDL_BUILD_DIR = . +IDL_EXPORT_DIR = . + +include $(IDL_MK_DIR)/idl.mk + +# Compound interfaces. + +pager_object_NAME = PagerObject +pager_object_INTERFACES = region_mapper system_pager + +COMP_INTERFACES_CC = pager_object + +# Individual interfaces. + +CLIENT_INTERFACES_CC = dataspace mapped_file -PRIVATE_INCDIR += $(PKGDIR)/include/exec +SERVER_INTERFACES_CC = $(call common_interfaces,$(COMP_INTERFACES_CC)) + +# Generated and plain source files. + +CLIENT_INTERFACES_SRC_CC = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC)) + +SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC) $(COMP_INTERFACES_CC)) + +# Normal source files. + +PLAIN_SRC_CC = elf.cc memory.cc pager.cc process.cc segment.cc stack.cc + +# Normal definitions. + +SRC_CC = \ + $(CLIENT_INTERFACES_SRC_CC) \ + $(SERVER_INTERFACES_SRC_CC) \ + $(PLAIN_SRC_CC) + +REQUIRES_LIBS = l4re_c-util libmem libipc libstdc++ libsystypes libfsclient + +PRIVATE_INCDIR = $(PKGDIR)/include/exec $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR) + CONTRIB_INCDIR = libexec include $(L4DIR)/mk/lib.mk +include $(IDL_MK_DIR)/interface_rules.mk + +$(PLAIN_SRC_CC): $(CLIENT_INTERFACES_SRC_CC) + +$(PLAIN_SRC_CC): $(SERVER_INTERFACES_SRC_CC) diff -r e54ba46787b6 -r 2b7f6a88332e libexec/lib/src/pager.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/lib/src/pager.cc Mon Jun 06 01:02:59 2022 +0200 @@ -0,0 +1,255 @@ +/* + * A system pager implementation. + * + * Copyright (C) 2022 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 + +#include +#include + +#include +#include + +#include "pager.h" +#include "pager_object_server.h" + + + +/* A simple system pager also acting as a region mapper. */ + +/* Add a region to the pager. */ + +void ExecPager::add(MappedRegion region) +{ + _regions[region.map_start] = region; +} + +/* Handle a general exception. */ + +long ExecPager::exception(l4_exc_regs_t regs, l4_snd_fpage_t *region) +{ + (void) region; + + printf("exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(®s), l4_utcb_exc_pc(®s)); + + 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); + + return L4_EOK; +} + +#define DEBUG 0 + +/* Handle a page fault using any configured regions. */ + +long ExecPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region) +{ + l4_umword_t addr = pfa & ~7UL, flags = pfa & 7; + +#if DEBUG + printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags); +#endif + + MappedRegions::iterator it = _regions.upper_bound(addr); + + if (it != _regions.begin()) + it--; + else + { + printf("not mapped!\n"); + return -L4_ENOMEM; + } + + MappedRegion &r = it->second; + + if ((addr >= r.map_start) && (addr < r.map_start + r.size)) + { + l4_addr_t page_addr = trunc(addr, L4_PAGESIZE); + + region->fpage = l4_fpage(r.start + (page_addr - r.map_start), L4_PAGESHIFT, r.flags); + region->snd_base = page_addr; + +#if DEBUG + printf("%lx...%lx from %lx...%lx offset %lx size %d rights %x\n", + r.map_start, region->snd_base, + r.start, l4_fpage_memaddr(region->fpage), + addr - r.map_start, + l4_fpage_size(region->fpage), + l4_fpage_rights(region->fpage)); + + 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("\n"); +#endif + + if (r.flags & L4RE_RM_F_W) + l4_touch_rw((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE); + else + l4_touch_ro((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE); + + return L4_EOK; + } + +#if DEBUG + printf("not mapped!\n"); +#endif + + return -L4_ENOMEM; +} + +/* Attach a region for provision when page faults occur. This is required in + the initialisation of a program by the C library which requires a region + mapper. */ + +long ExecPager::attach(address_t *start, offset_t size, map_flags_t flags, + 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; + + offset_t increment = 1UL << align; + offset_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. */ + + 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; + } + + /* 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); + + if (err) + return err; + + l4_touch_rw((const void *) ds_start, size); + +#if DEBUG + printf("-> added region for %lx size %ld (%d)\n", region_start, region_size, page_order(region_size)); +#endif + + add(MappedRegion(ds_start, region_size, flags & L4RE_DS_F_RIGHTS_MASK, region_start)); + + *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; + } +} + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r e54ba46787b6 -r 2b7f6a88332e tests/Makefile --- a/tests/Makefile Mon Jun 06 00:36:14 2022 +0200 +++ b/tests/Makefile Mon Jun 06 01:02:59 2022 +0200 @@ -28,25 +28,14 @@ include $(IDL_MK_DIR)/idl.mk -# Compound interfaces. - -pager_object_NAME = PagerObject -pager_object_INTERFACES = region_mapper system_pager - -COMP_INTERFACES_CC = pager_object - # Individual interfaces. CLIENT_INTERFACES_CC = dataspace mapped_file -SERVER_INTERFACES_CC = $(call common_interfaces,$(COMP_INTERFACES_CC)) - # Generated and plain source files. CLIENT_INTERFACES_SRC_CC = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC)) -SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC) $(COMP_INTERFACES_CC)) - # Normal source files. SRC_CC_dstest_block_client = dstest_block_client.cc @@ -73,8 +62,7 @@ SRC_CC_dstest_test_client = dstest_test_client.cc -PLAIN_SRC_CC_dstest_exec = dstest_exec.cc -SRC_CC_dstest_exec = $(PLAIN_SRC_CC_dstest_exec) $(SERVER_INTERFACES_SRC_CC) +SRC_CC_dstest_exec = dstest_exec.cc PLAIN_SRC_CC_dstest_file_mapping = dstest_file_mapping.cc SRC_CC_dstest_file_mapping = $(PLAIN_SRC_CC_dstest_file_mapping) $(CLIENT_INTERFACES_SRC_CC) @@ -86,5 +74,3 @@ include $(IDL_MK_DIR)/interface_rules.mk $(PLAIN_SRC_CC_dstest_file_mapping): $(CLIENT_INTERFACES_SRC_CC) - -$(PLAIN_SRC_CC_dstest_exec): $(SERVER_INTERFACES_SRC_CC) diff -r e54ba46787b6 -r 2b7f6a88332e tests/dstest_exec.cc --- a/tests/dstest_exec.cc Mon Jun 06 00:36:14 2022 +0200 +++ b/tests/dstest_exec.cc Mon Jun 06 01:02:59 2022 +0200 @@ -25,265 +25,19 @@ #include #include +#include #include -#include #include -#include - -#include #include -#include -#include #include #include -#include "pager_object_interface.h" #include "pager_object_server.h" -/* A simple system pager also acting as a region mapper. */ - -typedef std::map MappedRegions; - -class ExecPager : public PagerObject -{ -protected: - MappedRegions _regions; - -public: - virtual void add(MappedRegion region) - { - _regions[region.map_start] = region; - } - - /* Notification methods. */ - - virtual long exception(l4_exc_regs_t regs, - l4_snd_fpage_t *region); - - 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, offset_t size, map_flags_t flags, - l4_cap_idx_t ds, address_t offset, unsigned char align); - -}; - -/* Handle a general exception. */ - -long ExecPager::exception(l4_exc_regs_t regs, l4_snd_fpage_t *region) -{ - (void) region; - - printf("exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(®s), l4_utcb_exc_pc(®s)); - - 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); - - return L4_EOK; -} - -#define DEBUG 0 - -/* Handle a page fault using any configured regions. */ - -long ExecPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region) -{ - l4_umword_t addr = pfa & ~7UL, flags = pfa & 7; - -#if DEBUG - printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags); -#endif - - MappedRegions::iterator it = _regions.upper_bound(addr); - - if (it != _regions.begin()) - it--; - else - { - printf("not mapped!\n"); - return -L4_ENOMEM; - } - - MappedRegion &r = it->second; - - if ((addr >= r.map_start) && (addr < r.map_start + r.size)) - { - l4_addr_t page_addr = trunc(addr, L4_PAGESIZE); - - region->fpage = l4_fpage(r.start + (page_addr - r.map_start), L4_PAGESHIFT, r.flags); - region->snd_base = page_addr; - -#if DEBUG - printf("%lx...%lx from %lx...%lx offset %lx size %d rights %x\n", - r.map_start, region->snd_base, - r.start, l4_fpage_memaddr(region->fpage), - addr - r.map_start, - l4_fpage_size(region->fpage), - l4_fpage_rights(region->fpage)); - - 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("\n"); -#endif - - if (r.flags & L4RE_RM_F_W) - l4_touch_rw((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE); - else - l4_touch_ro((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE); - - return L4_EOK; - } - -#if DEBUG - printf("not mapped!\n"); -#endif - - return -L4_ENOMEM; -} - -/* Attach a region for provision when page faults occur. This is required in - the initialisation of a program by the C library which requires a region - mapper. */ - -long ExecPager::attach(address_t *start, offset_t size, map_flags_t flags, - 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; - - offset_t increment = 1UL << align; - offset_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. */ - - 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; - } - - /* 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); - - if (err) - return err; - - l4_touch_rw((const void *) ds_start, size); - -#if DEBUG - printf("-> added region for %lx size %ld (%d)\n", region_start, region_size, page_order(region_size)); -#endif - - add(MappedRegion(ds_start, region_size, flags & L4RE_DS_F_RIGHTS_MASK, region_start)); - - *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; - } -} - - - static ExecPager exec_pager;