# HG changeset patch # User Paul Boddie # Date 1611095209 -3600 # Node ID b257d5a9ff5913ab674110582896aa8e40d7a35a Dataspace testing again. diff -r 000000000000 -r b257d5a9ff59 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Tue Jan 19 23:26:49 2021 +0100 @@ -0,0 +1,41 @@ +PKGDIR ?= . +L4DIR ?= $(PKGDIR)/../.. + +TARGET = dstest_client dstest_server +MODE = shared + +# Locations for interface input and generated output. + +IDL_DIR = $(L4DIR)/pkg/libsystypes/idl +IDL_MK_DIR = $(L4DIR)/idl4re/mk +IDL_BUILD_DIR = . +IDL_EXPORT_DIR = . + +include $(IDL_MK_DIR)/idl.mk + +# Individual interfaces. + +SERVER_INTERFACES_CC = dataspace + +# Generated and plain source files. + +SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC)) + +PLAIN_SRC_CC = dstest_server.cc flexpage.cc memory_utils.cc region.cc + +# Normal definitions. + +SRC_CC_dstest_client = dstest_client.cc + +SRC_CC_dstest_server = \ + $(SERVER_INTERFACES_SRC_CC) \ + $(PLAIN_SRC_CC) + +REQUIRES_LIBS = l4re_c-util libipc libstdc++ + +PRIVATE_INCDIR = $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR) + +include $(L4DIR)/mk/prog.mk +include $(IDL_MK_DIR)/interface_rules.mk + +$(PLAIN_SRC_CC): $(SERVER_INTERFACES_SRC_CC) diff -r 000000000000 -r b257d5a9ff59 conf/dstest.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/dstest.cfg Tue Jan 19 23:26:49 2021 +0100 @@ -0,0 +1,23 @@ +-- vim:set ft=lua: + +local L4 = require("L4"); + +local l = L4.default_loader; + +local server = l:new_channel(); + +l:start({ + caps = { + server = server:svr(), + }, + log = { "server", "r" }, + }, + "rom/dstest_server"); + +l:start({ + caps = { + server = server, + }, + log = { "client", "g" }, + }, + "rom/dstest_client"); diff -r 000000000000 -r b257d5a9ff59 conf/dstest.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/dstest.list Tue Jan 19 23:26:49 2021 +0100 @@ -0,0 +1,25 @@ +entry dstest +roottask moe rom/dstest.cfg +module dstest.cfg +module l4re +module ned +module dstest_client +module dstest_server +module lib4re-c.so +module lib4re-c-util.so +module lib4re.so +module lib4re-util.so +module libc_be_l4refile.so +module libc_be_l4re.so +module libc_be_socket_noop.so +module libc_support_misc.so +module libdl.so +module libipc.so +module libl4sys-direct.so +module libl4sys.so +module libl4util.so +module libld-l4.so +module libpthread.so +module libstdc++.so +module libsupc++.so +module libuc_c.so diff -r 000000000000 -r b257d5a9ff59 dstest_client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dstest_client.cc Tue Jan 19 23:26:49 2021 +0100 @@ -0,0 +1,59 @@ +/* + * Test dataspace operations. + * + * Copyright (C) 2020, 2021 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 + + + +int main(void) +{ + l4_cap_idx_t server = l4re_env_get_cap("server"); + + /* Some memory to be mapped. */ + + char *memory; + unsigned long size = 40960; + long err = ipc_attach_dataspace(server, size, (void **) &memory); + + if (err) + { + printf("Could not map memory: %s\n", l4sys_errtostr(err)); + return 1; + } + + printf("Mapped memory at %p\n", memory); + + for (unsigned long offset = 0; offset < size; offset += 1024) + { + printf("10 bytes from %p...\n", (memory + offset)); + fwrite((memory + offset), sizeof(char), 10, stdout); + fputs("\n", stdout); + } + + return 0; +} diff -r 000000000000 -r b257d5a9ff59 dstest_server.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dstest_server.cc Tue Jan 19 23:26:49 2021 +0100 @@ -0,0 +1,125 @@ +/* + * Test dataspace operations. + * + * Copyright (C) 2020 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 "dataspace_server.h" +#include "flexpage.h" + + + +/* Component interface. */ + +class DataspaceServer : public Dataspace +{ +protected: + Region *_region; + offset_t _start, _size; + +public: + explicit DataspaceServer(char *addr, offset_t size) + { + _region = new Region((offset_t) addr, (offset_t) addr + size); + _start = 0; + _size = size; + + offset_t i; + int j; + + for (i = 0, j = 0; i < size; i += PAGE_SIZE, j++) + memset((void *) (addr + i), (int) 'a' + j, PAGE_SIZE); + } + + virtual long map(unsigned long offset, l4_addr_t hot_spot, unsigned long flags, l4_snd_fpage_t *region) + { + Flexpage flexpage(_region); + offset_t max_offset = _start + _size; + + printf("map(%ld, %lx, %lx, ...)\n", offset, hot_spot, flags); + + flexpage.reset(_start + offset); + + SendFlexpage send_flexpage = flexpage.to_send(offset, hot_spot, max_offset); + + printf("send %lx -> %lx -> {%lx, %d}\n", _region->start, flexpage.base_addr, send_flexpage.base_addr, send_flexpage.order); + + /* Send the flexpage explicitly. */ + + region->fpage = l4_fpage(send_flexpage.base_addr, send_flexpage.order, + (flags & L4RE_DS_MAP_FLAG_RW) ? L4_FPAGE_RW + : L4_FPAGE_RO); + region->snd_base = hot_spot; + + long err = complete_Dataspace_map(*region); + + if (err) + return err; + + return IPC_MESSAGE_SENT; + } +}; + + + +int main(void) +{ + /* Some memory. */ + + char *memory; + + if (posix_memalign((void **) &memory, 40960, 40960)) + { + printf("Could not allocate memory.\n"); + return 1; + } + + /* Dataspace encapsulation. */ + + DataspaceServer obj(memory, 40960); + + /* Server capability. */ + + l4_cap_idx_t server; + + /* Register a server associating it with the given object. */ + + long err = ipc_server_bind("server", (l4_umword_t) &obj, &server); + + if (err) + { + printf("Could not bind server: %s\n", l4sys_errtostr(err)); + return 1; + } + + /* Wait for messages, dispatching to the handler. */ + + ipc_server_loop(Dataspace_expected_items, &obj, + (ipc_server_handler_type) handle_Dataspace); + + return 0; +} diff -r 000000000000 -r b257d5a9ff59 flexpage.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flexpage.cc Tue Jan 19 23:26:49 2021 +0100 @@ -0,0 +1,140 @@ +#include +#include + +#include "flexpage.h" + + + +/* Reset the flexpage using 'offset', being the file offset. */ + +void Flexpage::reset(offset_t offset) +{ + _counter = 0; + + /* By definition (see "Flexible-Sized Page Objects - Object-Orientation + in Operation Systems"), flexpages are aligned to multiples of their + size. + + The size of the flexpage depends on the amount of space around the + accessed page. It cannot exceed the size of the memory region. */ + + size = max_multiple(region->start, region->end, PAGE_SIZE); + + /* The base address of the flexpage is computed from the region start + and flexpage size. It will be no lower than the region start. + + Sent flexpages may use higher bases due to receive window constraints, + these being communicated by the "hot spot". */ + + base_addr = round(region->start, size); + + /* Get the file offset for the base of the flexpage. This will be a + multiple of the flexpage size for alignment purposes. */ + + base_offset = trunc(offset, size); + + /* The page being accessed is relative to the base. + (This is transient information recording the initialising access + details.) */ + + page_offset = trunc(offset - base_offset, PAGE_SIZE); + page_addr = base_addr + page_offset; +} + +bool Flexpage::decrement() +{ + if (_counter) + { + _counter--; + return _counter == 0; + } + else + return 0; +} + +void Flexpage::increment() +{ + _counter++; +} + +void Flexpage::invalidate() +{ + _counter = 0; +} + +bool Flexpage::valid() +{ + return _counter != 0; +} + +/* Return whether the flexpage supports the given file 'position'. */ + +bool Flexpage::supports_position(offset_t position) +{ + return (base_offset <= position) && (position < (base_offset + size)); +} + +/* Return a "send" flexpage for an access to 'offset' by positioning it relative + to 'hot_spot' for the receive flexpage window. */ + +SendFlexpage Flexpage::to_send(offset_t offset, offset_t hot_spot, offset_t max_offset) +{ + /* The dataspace offset of the flexpage base is a multiple of the flexpage + size. */ + + offset_t receive_base_offset = trunc(offset, size); + + /* The offset of the accessed page within the flexpage is constrained by the + current flexpage size. */ + + offset_t page_offset = trunc(offset - receive_base_offset, PAGE_SIZE); + + /* The receive flexpage offset (hot spot) must be constrained to the + flexpage, both the size and the start. */ + + offset_t receive_size; + + if (max_offset) + receive_size = std::min(size, max_offset - receive_base_offset); + else + receive_size = size; + + offset_t receive_page_offset = hot_spot % receive_size; + + while ((receive_size > PAGE_SIZE) && (receive_page_offset != page_offset)) + { + receive_size /= 2; + receive_page_offset = hot_spot % receive_size; + } + + /* The flexpage base address is adjusted using the difference in page + offsets. Where the receive flexpage offset is constained further, the + base address will be raised to become closer to the accessed page. */ + + offset_t adjustment = page_offset - receive_page_offset; + + return SendFlexpage(base_addr + adjustment, page_order(receive_size)); +} + +/* Return a representation of the flexpage for unmapping. */ + +SendFlexpage Flexpage::to_unmap() +{ + return SendFlexpage(base_addr, page_order(size)); +} + +/* Debugging methods. */ + +void Flexpage::show(std::ostringstream &buffer) +{ + char buf[256]; + + snprintf(buf, 256, "Flexpage(base_offset=0x%lx/%ld, " + "base_addr=0x%lx, size=0x%lx/%ld)", + base_offset, base_offset, base_addr, + size, size); + + buffer << buf; +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 000000000000 -r b257d5a9ff59 flexpage.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flexpage.h Tue Jan 19 23:26:49 2021 +0100 @@ -0,0 +1,57 @@ +#pragma once + +#include + +#include "memory_utils.h" +#include "region.h" +#include "send_flexpage.h" + + + +/* A flexpage abstraction. */ + +class Flexpage +{ +protected: + unsigned int _counter; + +public: + Region *region; + + /* General flexpage characteristics. */ + + offset_t base_addr, size; + offset_t base_offset; + + /* Transient debugging information. */ + + offset_t page_addr, page_offset; + + /* Associate a flexpage with a memory 'region'. */ + + explicit Flexpage(Region *region) : region(region) + { + } + + void reset(offset_t offset); + + bool decrement(); + + void increment(); + + void invalidate(); + + bool valid(); + + bool supports_position(offset_t position); + + SendFlexpage to_send(offset_t offset, offset_t hot_spot, offset_t max_offset=0); + + SendFlexpage to_unmap(); + + /* Debugging methods. */ + + void show(std::ostringstream &buffer); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 000000000000 -r b257d5a9ff59 memory_utils.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/memory_utils.cc Tue Jan 19 23:26:49 2021 +0100 @@ -0,0 +1,111 @@ +#include "memory_utils.h" + + + +/* Return page 'n' for the configured page size. */ + +offset_t page(unsigned int n) +{ + return PAGE_SIZE * n; +} + +/* Return the order of 'size', where 2 ** order yields the size. */ + +unsigned int page_order(offset_t size) +{ + /* Count zeros from the left, stopping at the first set bit, using the width + of the size value (in bits, starting with the width in bytes) to + calculate the position of this bit and thus the order of the value. */ + + return sizeof(unsigned long) * 8 - 1 - __builtin_clzl(size); +} + +/* Return 'value' rounded up to the nearest 'increment'. */ + +offset_t round(offset_t value, offset_t increment) +{ + return trunc(value + increment - 1, increment); +} + +/* Return 'value' rounded up to the nearest multiple of 'increment'. */ + +offset_t round_multiple(offset_t value, offset_t increment) +{ + offset_t last = increment; + + while (1) + { + if (value < increment) + return round(value, last); + + last = increment; + increment *= 2; + } +} + +/* Return 'value' rounded down (or truncated) to the nearest 'increment'. */ + +offset_t trunc(offset_t value, offset_t increment) +{ + return (value / increment) * increment; +} + +/* Return 'value' rounded down (or truncated) to the nearest multiple of + 'increment'. */ + +offset_t trunc_multiple(offset_t value, offset_t increment) +{ + offset_t last = increment; + + while (1) + { + if (value < increment) + return trunc(value, last); + + last = increment; + increment *= 2; + } +} + +/* Find the maximum size aligned region within the region from 'start' to (but + not including) 'end', with the given initial 'increment'. */ + +offset_t max_multiple(offset_t start, offset_t end, offset_t increment) +{ + /* The largest possible aligned region is derived from the region size. */ + + offset_t size = trunc_multiple(end - start, increment); + + /* Apply the alignment to the start. */ + + offset_t aligned = round(start, size); + + /* If the region is aligned, return the size. */ + + if (aligned == start) + return size; + + /* If the region is not aligned to the current size, recalculate the aligned + size. */ + + offset_t aligned_size; + + do + { + aligned_size = trunc_multiple(end - aligned, increment); + size /= 2; + + /* Determine whether a smaller alignment could yield a larger aligned + size. */ + + if (aligned_size >= size) + return aligned_size; + + aligned = round(start, size); + } + while (aligned > start); + + return aligned_size; +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 000000000000 -r b257d5a9ff59 memory_utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/memory_utils.h Tue Jan 19 23:26:49 2021 +0100 @@ -0,0 +1,25 @@ +#pragma once + +#include "types.h" + +#define PAGE_SIZE 4096 + + + +/* Address arithmetic. */ + +offset_t page(unsigned int n); + +unsigned int page_order(offset_t size); + +offset_t round(offset_t value, offset_t increment); + +offset_t round_multiple(offset_t value, offset_t increment); + +offset_t trunc(offset_t value, offset_t increment); + +offset_t trunc_multiple(offset_t value, offset_t increment); + +offset_t max_multiple(offset_t start, offset_t end, offset_t increment); + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 000000000000 -r b257d5a9ff59 region.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/region.cc Tue Jan 19 23:26:49 2021 +0100 @@ -0,0 +1,90 @@ +#include +#include +#include + +#include "region.h" + + + +/* Initialise region state, indicating the size, file and position. */ + +RegionState::RegionState(unsigned long size, fileid_t fileid, offset_t filepos) +: size(size), fileid(fileid), filepos(filepos) +{ +} + +void RegionState::fill(fileid_t fileid, offset_t filepos) +{ + this->fileid = fileid; + this->filepos = filepos; +} + +void RegionState::show(std::ostringstream &buffer) +{ + char buf[64]; + + snprintf(buf, 64, "{%3ld:%6ld}", fileid, filepos); + + buffer << buf; +} + + + +/* Initialise a region having the given 'start' and 'end' addresses, with the + 'end' being one location beyond the last address in the region. */ + +Region::Region(offset_t start, offset_t end) +: start(start), end(end), state(end - start) +{ + /* Content state. */ + + memset((void *) start, 0, end - start); +} + +Region::~Region() +{ + free((void *) start); +} + +offset_t Region::size() +{ + return end - start; +} + +/* Debugging methods. */ + +int Region::compare(Region *other) +{ + if (start < other->start) + return -1; + else if (start > other->start) + return 1; + else + return 0; +} + +void Region::fill(fileid_t fileid, offset_t filepos) +{ + state.fill(fileid, filepos); +} + +void Region::flush() +{ +} + +/* Simulation methods. */ + +char *Region::read(offset_t offset) +{ + return (char *) start + offset; +} + +void Region::write(const char *data, offset_t offset) +{ + size_t length = strlen(data); + + if (offset + length < size()) + memcpy((void *) (start + offset), data, length + 1); +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 000000000000 -r b257d5a9ff59 region.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/region.h Tue Jan 19 23:26:49 2021 +0100 @@ -0,0 +1,62 @@ +#pragma once + +#include +#include + +#include "types.h" + + + +/* Region-related state information. */ + +class RegionState +{ +public: + unsigned long size; + fileid_t fileid; + offset_t filepos; + + explicit RegionState(unsigned long size=0, fileid_t fileid=0, offset_t filepos=0); + + void fill(fileid_t fileid, offset_t filepos); + + void show(std::ostringstream &buffer); + + bool valid() { return size != 0; } +}; + + + +/* A memory region abstraction. */ + +class Region +{ +public: + offset_t start, end; + + /* Debugging information. */ + + RegionState state; + + /* Methods. */ + + explicit Region(offset_t start, offset_t end); + + virtual ~Region(); + + offset_t size(); + + int compare(Region *other); + + void fill(fileid_t fileid, offset_t filepos); + + void flush(); + + /* Simulation methods. */ + + char *read(offset_t offset=0); + + void write(const char *data, offset_t offset=0); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 000000000000 -r b257d5a9ff59 send_flexpage.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/send_flexpage.h Tue Jan 19 23:26:49 2021 +0100 @@ -0,0 +1,19 @@ +#pragma once + +#include "types.h" + +/* A "send" flexpage abstraction. */ + +class SendFlexpage +{ +public: + offset_t base_addr; + unsigned int order; + + explicit SendFlexpage(offset_t base_addr, unsigned int order) + : base_addr(base_addr), order(order) + { + } +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 000000000000 -r b257d5a9ff59 types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/types.h Tue Jan 19 23:26:49 2021 +0100 @@ -0,0 +1,13 @@ +#pragma once + +/* File identification. */ + +typedef unsigned long fileid_t; + +#define FILEID_INVALID (~0UL) + +/* File and memory region offsets. */ + +typedef unsigned long offset_t; + +// vim: tabstop=4 expandtab shiftwidth=4