1.1 --- a/conf/dstest_exec.cfg Sun Jun 12 17:10:30 2022 +0200
1.2 +++ b/conf/dstest_exec.cfg Wed Aug 10 00:25:44 2022 +0200
1.3 @@ -34,7 +34,7 @@
1.4 },
1.5 log = { "ext2svr", "y" },
1.6 },
1.7 - "rom/dstest_ext2_server", "blocksvr", "rom/e2test.fs", "10", "ext2svr");
1.8 + "rom/dstest_ext2_server", "blocksvr", "rom/e2test.fs", "20", "ext2svr");
1.9
1.10 -- Obtain user filesystems with umask 0022 (18).
1.11
1.12 @@ -47,4 +47,4 @@
1.13 },
1.14 log = { "client", "g" },
1.15 },
1.16 - "rom/dstest_exec", "home/paulb/dstest_exec_payload", "hello", "world");
1.17 + "rom/dstest_exec", "home/paulb/exec_region_mapper", "home/paulb/dstest_exec_payload", "hello", "world");
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/conf/dstest_file_mapping.cfg Wed Aug 10 00:25:44 2022 +0200
2.3 @@ -0,0 +1,23 @@
2.4 +-- vim:set ft=lua:
2.5 +
2.6 +local L4 = require("L4");
2.7 +
2.8 +local l = L4.default_loader;
2.9 +
2.10 +local server = l:new_channel();
2.11 +
2.12 +l:startv({
2.13 + caps = {
2.14 + server = server:svr(),
2.15 + },
2.16 + log = { "server", "r" },
2.17 + },
2.18 + "rom/dstest_host_server", "10");
2.19 +
2.20 +l:startv({
2.21 + caps = {
2.22 + server = server,
2.23 + },
2.24 + log = { "client", "g" },
2.25 + },
2.26 + "rom/dstest_file_mapping", "rom/dstest_file_mapping.cfg", 1024, 1024);
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/conf/dstest_file_mapping.list Wed Aug 10 00:25:44 2022 +0200
3.3 @@ -0,0 +1,25 @@
3.4 +entry dstest_file_mapping
3.5 +roottask moe rom/dstest_file_mapping.cfg
3.6 +module dstest_file_mapping.cfg
3.7 +module l4re
3.8 +module ned
3.9 +module dstest_file_mapping
3.10 +module dstest_host_server
3.11 +module lib4re-c.so
3.12 +module lib4re-c-util.so
3.13 +module lib4re.so
3.14 +module lib4re-util.so
3.15 +module libc_be_l4refile.so
3.16 +module libc_be_l4re.so
3.17 +module libc_be_socket_noop.so
3.18 +module libc_support_misc.so
3.19 +module libdl.so
3.20 +module libipc.so
3.21 +module libl4sys-direct.so
3.22 +module libl4sys.so
3.23 +module libl4util.so
3.24 +module libld-l4.so
3.25 +module libpthread.so
3.26 +module libstdc++.so
3.27 +module libsupc++.so
3.28 +module libuc_c.so
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/conf/dstest_file_remove.cfg Wed Aug 10 00:25:44 2022 +0200
4.3 @@ -0,0 +1,51 @@
4.4 +-- vim:set ft=lua:
4.5 +
4.6 +local L4 = require("L4");
4.7 +
4.8 +local l = L4.default_loader;
4.9 +
4.10 +local pipe_server = l:new_channel();
4.11 +
4.12 +l:startv({
4.13 + caps = {
4.14 + server = pipe_server:svr(),
4.15 + },
4.16 + log = { "pipes", "r" },
4.17 + },
4.18 + "rom/dstest_pipe_server", "10");
4.19 +
4.20 +local block_server = l:new_channel();
4.21 +
4.22 +l:startv({
4.23 + caps = {
4.24 + server = block_server:svr(),
4.25 + },
4.26 + log = { "blocksvr", "r" },
4.27 + },
4.28 + "rom/dstest_block_server", "10");
4.29 +
4.30 +local ext2svr = l:new_channel();
4.31 +
4.32 +l:startv({
4.33 + caps = {
4.34 + blocksvr = block_server,
4.35 + pipes = pipe_server,
4.36 + ext2svr = ext2svr:svr(),
4.37 + },
4.38 + log = { "ext2svr", "y" },
4.39 + },
4.40 + "rom/dstest_ext2_server", "blocksvr", "rom/e2test.fs", "10", "ext2svr");
4.41 +
4.42 +-- Obtain user filesystems with umask 0022 (18).
4.43 +
4.44 +local open_for_user = 6;
4.45 +local ext2svr_paulb = L4.cast(L4.Proto.Factory, ext2svr):create(open_for_user, 1000, 1000, 18);
4.46 +
4.47 +l:startv({
4.48 + caps = {
4.49 + server = ext2svr_paulb,
4.50 + },
4.51 + log = { "client", "g" },
4.52 + },
4.53 + -- program, file to create and remove
4.54 + "rom/dstest_file_remove", "home/paulb/to_remove");
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/conf/dstest_file_remove.list Wed Aug 10 00:25:44 2022 +0200
5.3 @@ -0,0 +1,28 @@
5.4 +entry dstest_file_remove
5.5 +roottask moe rom/dstest_file_remove.cfg
5.6 +module dstest_file_remove.cfg
5.7 +module e2test.fs
5.8 +module l4re
5.9 +module ned
5.10 +module dstest_file_remove
5.11 +module dstest_ext2_server
5.12 +module dstest_block_server
5.13 +module dstest_pipe_server
5.14 +module lib4re-c.so
5.15 +module lib4re-c-util.so
5.16 +module lib4re.so
5.17 +module lib4re-util.so
5.18 +module libc_be_l4refile.so
5.19 +module libc_be_l4re.so
5.20 +module libc_be_socket_noop.so
5.21 +module libc_support_misc.so
5.22 +module libdl.so
5.23 +module libipc.so
5.24 +module libl4sys-direct.so
5.25 +module libl4sys.so
5.26 +module libl4util.so
5.27 +module libld-l4.so
5.28 +module libpthread.so
5.29 +module libstdc++.so
5.30 +module libsupc++.so
5.31 +module libuc_c.so
6.1 --- a/docs/wiki/ClientLibrary Sun Jun 12 17:10:30 2022 +0200
6.2 +++ b/docs/wiki/ClientLibrary Wed Aug 10 00:25:44 2022 +0200
6.3 @@ -15,6 +15,7 @@
6.4 The fields of the `file_t` data structure are as follows:
6.5
6.6 || '''Field''' || '''Description''' ||
6.7 +|| `ref` || A reference to the component providing file content ||
6.8 || `memory` || The memory address of the exposed file region ||
6.9 || `start_pos` || The start position of the region in the file ||
6.10 || `end_pos` || The end position of the region in the file ||
6.11 @@ -24,6 +25,7 @@
6.12 || `object_flags` || Flags indicating support for certain file features ||
6.13 || `can_block` || Notification flags for blocking access to the file ||
6.14 || `notifications`|| Notification flags set for the file ||
6.15 +|| `flags` || The flags used to open the file ||
6.16
6.17 == Client Programming Interface ==
6.18
7.1 --- a/docs/wiki/Components Sun Jun 12 17:10:30 2022 +0200
7.2 +++ b/docs/wiki/Components Wed Aug 10 00:25:44 2022 +0200
7.3 @@ -59,9 +59,9 @@
7.4 Object [label="MappedFile\nor\nDirectory"];
7.5 }
7.6
7.7 - Client1 -> Client2 -> Client3 -> Client4 -> Client5 -> Client6 -> Client7 [arrowhead=none,style=dotted];
7.8 - Opener1 -> Opener2 [arrowhead=none,style=dotted];
7.9 - OpenerContext1 -> OpenerContext2 -> OpenerContext3 [arrowhead=none,style=dotted];
7.10 + Client1 -> Client2 -> Client3 -> Client4 -> Client5 -> Client6 -> Client7 [dir=none,style=dotted];
7.11 + Opener1 -> Opener2 [dir=none,style=dotted];
7.12 + OpenerContext1 -> OpenerContext2 -> OpenerContext3 [dir=none,style=dotted];
7.13
7.14 Client1 -> Filesystem [label="open_for_user(user)"];
7.15 Filesystem -> Opener1;
7.16 @@ -129,8 +129,8 @@
7.17 }
7.18 }
7.19
7.20 - Client1 -> Client2 -> Client3 -> Client4 [arrowhead=none,style=dotted];
7.21 - Reader1 -> Reader2 -> Reader3 [arrowhead=none,style=dotted];
7.22 + Client1 -> Client2 -> Client3 -> Client4 [dir=none,style=dotted];
7.23 + Reader1 -> Reader2 -> Reader3 [dir=none,style=dotted];
7.24
7.25 Client1 -> Directory [label="opendir()"];
7.26 Directory -> Reader1;
7.27 @@ -251,6 +251,7 @@
7.28
7.29 {{{
7.30 mmap(in offset_t position, in offset_t length,
7.31 + in offset_t start_visible, in offset_t end_visible,
7.32 out offset_t start_pos, out offset_t end_pos,
7.33 out offset_t size)
7.34 }}}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/docs/wiki/Directories Wed Aug 10 00:25:44 2022 +0200
8.3 @@ -0,0 +1,273 @@
8.4 += Directories =
8.5 +
8.6 +Filesystem directories contain collections of files, other directories, along
8.7 +with other filesystem objects. Directories can be listed, permitting
8.8 +filesystem clients to peruse the contents of each directory. However, the act
8.9 +of listing a directory may impose certain constraints on the operations being
8.10 +conducted on the directory during the listing process.
8.11 +
8.12 +Operations that affect directory contents include the following:
8.13 +
8.14 + * Creating a new object
8.15 + * Removing an object
8.16 + * Moving an object out of the directory
8.17 + * Moving an object into the directory
8.18 +
8.19 +It is conceivable that for some filesystems, these operations will not be able
8.20 +to rely on directly modifying the directory since a listing operation may be
8.21 +in progress. Consequently, a number of rules would be imposed for such
8.22 +filesystems. It appears that Ext2-based filesystems accessed via libext2fs do
8.23 +not require such rules to be applied outside the library due to the design of
8.24 +the filesystem structures and the behaviour of the library itself.
8.25 +
8.26 +== Providers ==
8.27 +
8.28 +Providers of filesystem objects are created when at least one filesystem
8.29 +client is accessing such an object, with the object regarded as being
8.30 +'''open'''. By definition, a provider will exist until all clients have closed
8.31 +or discarded their means of accessing the object.
8.32 +
8.33 +An object is regarded as '''accessible''' if it can still be opened by
8.34 +filesystem clients. Where an object has been removed, it will no longer be
8.35 +accessible since clients should not be able to see the object in the
8.36 +filesystem any more. (The actual filesystem residing in storage may not have
8.37 +been updated for such a removal, this being the eventual outcome of a removal
8.38 +operation.)
8.39 +
8.40 +Providers can be regarded as '''accessible''' if they maintain access to
8.41 +objects that are open and accessible. Clients opening objects will only gain
8.42 +access to accessible providers. Providers can become inaccessible if an object
8.43 +is removed even if the object (and its provider) is still open.
8.44 +
8.45 +Initially, providers will correspond to objects resident in the stored
8.46 +filesystem. Thus, looking up an object using its path will involve the
8.47 +filesystem, yielding a file identifier that can be used to map to a provider.
8.48 +
8.49 +{{{
8.50 +def get_provider_from_filesystem(path):
8.51 + fileid = opening.get_fileid(path)
8.52 +
8.53 + if not fileid:
8.54 + return error
8.55 +
8.56 + return find_provider(fileid)
8.57 +}}}
8.58 +
8.59 +However, providers may not always immediately correspond to objects resident
8.60 +in the stored filesystem. Where an object is created but cannot be immediately
8.61 +registered in the contents of a directory, it must be registered separately
8.62 +and attempts to open this object must consult this separate mapping of
8.63 +filenames to providers.
8.64 +
8.65 +{{{
8.66 +def get_provider(path):
8.67 + provider = find_created_provider(path)
8.68 +
8.69 + if provider:
8.70 + return provider
8.71 +
8.72 + return get_provider_from_filesystem(path)
8.73 +}}}
8.74 +
8.75 +Providers that are inaccessible need to be retained until they are closed.
8.76 +However, since they are no longer accessible, they should not be available to
8.77 +the provider lookup operations.
8.78 +
8.79 +When providers are closed, they are removed from any mapping in which they
8.80 +could be found. Inaccessible providers that have been retained outside the
8.81 +identifier or filename mappings will represent objects that should be removed
8.82 +from their parent directory. Accessible providers retained by the mappings
8.83 +will represent objects that should be created in their parent directory.
8.84 +
8.85 +Whether object removal or creation will occur depends on whether the parent
8.86 +directory is able to safely perform these operations concurrently with other
8.87 +operations (such as servicing a listing operation) or whether such operations
8.88 +will need to be deferred until they can be safely performed.
8.89 +
8.90 +== Object Removal ==
8.91 +
8.92 +Filesystem object removal involves obtaining any provider of the object. Where
8.93 +a provider can be obtained, it will be made inaccessible and removal will be
8.94 +requested. The actual object will not be removed at least until it is closed
8.95 +because it may still receive and provide data. (Unlinking open files is a
8.96 +feature of Unix systems.)
8.97 +
8.98 +Where a provider cannot be obtained, an attempt will be made to obtain the
8.99 +parent directory provider, and if this succeeds, it indicates that the
8.100 +directory is being accessed and must therefore be notified of the intention to
8.101 +eventually remove the object concerned.
8.102 +
8.103 +Without any provider of the object, and where no directory provider can be
8.104 +obtained, the object can be immediately removed from the filesystem.
8.105 +
8.106 +{{{
8.107 +def remove_object(path):
8.108 + provider = get_provider(path)
8.109 +
8.110 + if provider:
8.111 + return make_provider_inaccessible(provider)
8.112 +
8.113 + dirname, basename = split(path)
8.114 + directory_provider = get_provider(dirname)
8.115 +
8.116 + if directory_provider:
8.117 + return directory_provider.remove_pending(basename)
8.118 +
8.119 + return filesystem.remove_object(path)
8.120 +}}}
8.121 +
8.122 +It should be noted that with no accessible provider, any attempt to create a
8.123 +file with the same name as a removed file should cause a new "version" of the
8.124 +file to be created.
8.125 +
8.126 +== Object Creation ==
8.127 +
8.128 +Filesystem object creation occurs when no existing provider can be found for a
8.129 +named object and where creation is requested. Any new object will be
8.130 +accessible and remain so until or unless it is removed.
8.131 +
8.132 +Whether an object is created in the filesystem storage depends on whether the
8.133 +parent directory is being used.
8.134 +
8.135 +If a parent directory is not being used, the object can be registered in its
8.136 +proper location in the filesystem itself, yielding a file identifier.
8.137 +
8.138 +If a parent directory is being used, the object cannot be immediately
8.139 +registered in its proper location, but since data may still need to be written
8.140 +to storage, a temporary location is employed, yielding a file identifier.
8.141 +
8.142 +For an object created in a temporary location, a temporary mapping from the
8.143 +path of the object to the provider is established, with the parent directory
8.144 +being notified of the pending object creation.
8.145 +
8.146 +{{{
8.147 +def create_object(path):
8.148 + provider = get_provider(path)
8.149 +
8.150 + if provider:
8.151 + return error
8.152 +
8.153 + dirname, basename = split(path)
8.154 + directory_provider = get_provider(dirname)
8.155 +
8.156 + if directory_provider:
8.157 + provider = make_provider(get_temporary_location(path))
8.158 + directory_provider.create_pending(provider)
8.159 + return register_created_provider(path, provider)
8.160 +
8.161 + provider = make_provider(path)
8.162 + return register_provider(provider)
8.163 +}}}
8.164 +
8.165 +== Created Providers ==
8.166 +
8.167 +Created providers are retained by the registry until their files can be
8.168 +committed to the filesystem in the desired location.
8.169 +
8.170 +The `register_created_provider` operation establishes a mapping from a path to
8.171 +a provider that can be queried using the `find_created_provider` operation.
8.172 +
8.173 +Created providers are deregistered when they are closed. This will occur when
8.174 +the parent directory of the file to be committed is closed. At that time, the
8.175 +created file will be moved from its temporary location to the desired
8.176 +location.
8.177 +
8.178 +== Inaccessible Providers ==
8.179 +
8.180 +Inaccessible providers are retained by the registry until they are closed.
8.181 +
8.182 +Where the provided file resides in a non-temporary location, closure will
8.183 +occur when the parent directory of the provided file is closed, this having
8.184 +obstructed the removal of the file. At that time, the provided file will be
8.185 +removed.
8.186 +
8.187 +Where the provided file resides in a temporary location, closure will not be
8.188 +obstructed by any directory and will cause the file to be removed immediately.
8.189 +
8.190 +== Directory Provider Closure ==
8.191 +
8.192 +A critical event that typically initiates housekeeping work for created and
8.193 +removed files is the closure of the parent directory of those files.
8.194 +
8.195 +Directory providers support the `create_pending` and `remove_pending`
8.196 +operations that register the details of affected files. When closure occurs,
8.197 +the provider will contact the registry to initiate the necessary work to
8.198 +relocate created files and to remove files.
8.199 +
8.200 +
8.201 +
8.202 +
8.203 + Where an object provider is notified of pending removal, it will initiate
8.204 + removal of the actual object upon closure, checking for an active parent
8.205 + provider.
8.206 +
8.207 + Where a parent provider is notified of pending removal, it will initiate
8.208 + removal of the actual object upon closure, checking for an active object
8.209 + provider.
8.210 +
8.211 + Object opening logic would need to be adjusted. Consider the case where a
8.212 + file is removed but still open.
8.213 +
8.214 + Any attempt to open a file with the same name must ignore the original and
8.215 + open a new file of that name which would be stored elsewhere until such
8.216 + time as the original is actually removed from its location.
8.217 +
8.218 + This new file might have a different identifier since the original file
8.219 + would still exist and retain the identifier.
8.220 +
8.221 + Any such new, but uncommitted, file must be accessible by other clients
8.222 + attempting to open a file of that name. However, removal operations must
8.223 + also be possible, making this version of the open file also unaccessible
8.224 + to new opening clients.
8.225 +
8.226 + Therefore, any providers used by opening clients must only refer to a
8.227 + version of a file that is pending removal if no other version has been
8.228 + created. Once a new version has been created, any provider pending removal
8.229 + must be relegated to a separate collection.
8.230 +
8.231 + Storage of new versions of files could be confined to special directories
8.232 + that are hidden from clients.
8.233 +
8.234 + The opening logic would be as follows:
8.235 +
8.236 + provider = find_provider(path)
8.237 +
8.238 + if provider:
8.239 + if provider.pending_removal():
8.240 + relegate(provider)
8.241 + provider = create_provider(path, hidden=True)
8.242 + else:
8.243 + provider = create_provider(path, hidden=False)
8.244 +
8.245 + # Have provider.
8.246 +
8.247 + return provider.make_resource()
8.248 +
8.249 + A provider would normally be obtained by consulting the filesystem
8.250 + implementation. However, new versions of files replacing ones pending
8.251 + removal will reside in locations that are different to the intended
8.252 + location of the file. Consequently, the registry needs to maintain its own
8.253 + mapping of paths to providers for such file versions.
8.254 +
8.255 + The opportunity to remove a file definitively arises when the following
8.256 + conditions are satisfied:
8.257 +
8.258 + * The parent directory is not open in some way
8.259 + * The original provider for the file is no longer open
8.260 +
8.261 + For new versions of a removed file that have themselves been marked as
8.262 + pending removal, their closure is sufficient to remove their filesystem
8.263 + resources.
8.264 +
8.265 + However, the registry must maintain a path entry for any active version
8.266 + of a removed file until that version is closed. Thus, the following
8.267 + conditions apply:
8.268 +
8.269 + * The parent directory (of the original file) is not open in some way
8.270 + * The provider of the new version is no longer open
8.271 +
8.272 + It will not be generally possible to open the hidden directory containing
8.273 + new file versions. Therefore, the transfer of the file to its intended
8.274 + location will not risk interfering with any operations on the hidden
8.275 + directory.
8.276 +
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/docs/wiki/FilesystemAccess Wed Aug 10 00:25:44 2022 +0200
9.3 @@ -0,0 +1,611 @@
9.4 += Filesystem Access =
9.5 +
9.6 +Within the [[ServerLibrary|filesystem server library]], a number of different
9.7 +abstractions and mechanisms are employed to provide access to filesystem
9.8 +objects. An overview of these abstractions is presented below.
9.9 +
9.10 +######## A graph showing the relationships between filesystem access
9.11 +######## components
9.12 +
9.13 +{{{#!graphviz
9.14 +#format svg
9.15 +#transform notugly
9.16 +digraph components {
9.17 + node [fontsize="12.0",fontname="sans-serif",shape=box];
9.18 + edge [fontsize="12.0",fontname="sans-serif"];
9.19 + rankdir=LR;
9.20 +
9.21 + subgraph {
9.22 + rank=same;
9.23 +
9.24 + Opener_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfile open\noperation"];
9.25 + Opener;
9.26 +
9.27 + Opener_note -> Opener [dir=none,style=dotted];
9.28 + }
9.29 +
9.30 + subgraph {
9.31 + rank=same;
9.32 +
9.33 + ResourceRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen file\nsessions"];
9.34 + ResourceRegistry;
9.35 +
9.36 + ResourceRegistry_note -> ResourceRegistry [dir=none,style=dotted];
9.37 + }
9.38 +
9.39 + subgraph {
9.40 + rank=same;
9.41 +
9.42 + Resource_note [shape=note,style=filled,fillcolor=gold,label="Provides\nfilesystem\ncontent"];
9.43 + Resource [label="Resource\n(Pager)"];
9.44 +
9.45 + Resource_note -> Resource [dir=none,style=dotted];
9.46 + }
9.47 +
9.48 + subgraph {
9.49 + rank=same;
9.50 +
9.51 + Provider_note [shape=note,style=filled,fillcolor=gold,label="Represents\nopen file"];
9.52 + Provider;
9.53 +
9.54 + Provider_note -> Provider [dir=none,style=dotted];
9.55 + }
9.56 +
9.57 + subgraph {
9.58 + rank=same;
9.59 +
9.60 + PageMapper_note [shape=note,style=filled,fillcolor=gold,label="Provides\npopulated\nfile pages"];
9.61 + PageMapper;
9.62 +
9.63 + PageMapper_note -> PageMapper [dir=none,style=dotted];
9.64 + }
9.65 +
9.66 + ProviderRegistry [shape=record,label="<head> ProviderRegistry | ... | { file-n | provider-n } | ... "];
9.67 +
9.68 + subgraph {
9.69 + rank=same;
9.70 +
9.71 + FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"];
9.72 + FileOpening;
9.73 +
9.74 + FileOpening_note -> FileOpening [dir=none,style=dotted];
9.75 + }
9.76 +
9.77 + subgraph {
9.78 + rank=same;
9.79 +
9.80 + Accessor_note [shape=note,style=filled,fillcolor=gold,label="Populates\nfile pages"];
9.81 + Accessor;
9.82 + Accessor_note -> Accessor [dir=none,style=dotted];
9.83 + }
9.84 +
9.85 + /* Opening a file. */
9.86 +
9.87 + Opener -> ResourceRegistry -> Resource;
9.88 + ResourceRegistry -> FileOpening;
9.89 +
9.90 + Provider -> PageMapper;
9.91 + FileOpening -> Accessor;
9.92 +
9.93 + /* Closing a file. */
9.94 +
9.95 + Resource -> Provider -> ProviderRegistry:head;
9.96 +
9.97 + /* Open file management. */
9.98 +
9.99 + ResourceRegistry -> ProviderRegistry:head;
9.100 +}
9.101 +}}}
9.102 +
9.103 +########
9.104 +
9.105 +An `Opener` requests a `Resource` from a `ResourceRegistry`, each `Resource`
9.106 +acting as a [[ServerLibrary#Pager|`Pager`]] and providing the actual access
9.107 +mechanism to file content for a particular program. Since many programs may
9.108 +access the same file simultaneously, a `Provider` object represents a file
9.109 +opened in the system, retaining a `PageMapper` that coordinates the collective
9.110 +access to the file (see the [[Paging|paging documentation]] for more
9.111 +information).
9.112 +
9.113 +A `ProviderRegistry` maintains the record of opened files, yielding a new
9.114 +`Provider` for an unopened file or an existing `Provider` for a file that is
9.115 +already open. The `ProviderRegistry` monitors the usage of files, discarding
9.116 +any `Provider` no longer in use.
9.117 +
9.118 +== Opening Files ==
9.119 +
9.120 +Opening a file involves the identification of the filesystem object involved,
9.121 +the acquisition of a `Provider` representing the file, and the creation of a
9.122 +`Resource` to deliver file content to the requesting program.
9.123 +
9.124 +######## A graph showing the opening mechanism for an already-open file
9.125 +
9.126 +{{{#!graphviz
9.127 +#format svg
9.128 +#transform notugly
9.129 +digraph opening_open {
9.130 + node [fontsize="12.0",fontname="sans-serif",shape=box];
9.131 + edge [fontsize="12.0",fontname="sans-serif"];
9.132 + rankdir=LR;
9.133 +
9.134 + subgraph {
9.135 + rank=same;
9.136 +
9.137 + Opener_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfile open\noperation"];
9.138 + Opener;
9.139 +
9.140 + Opener_note -> Opener [dir=none,style=dotted];
9.141 + }
9.142 +
9.143 + subgraph {
9.144 + rank=same;
9.145 +
9.146 + ResourceRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen file\nsessions"];
9.147 + ResourceRegistry;
9.148 +
9.149 + Resource_returned [label="Resource\n(Pager)"];
9.150 + Resource_returned_note [shape=note,style=filled,fillcolor=gold,label="Provides\nfilesystem\ncontent"];
9.151 +
9.152 + ResourceRegistry_note -> ResourceRegistry [dir=none,style=dotted];
9.153 + Resource_returned -> Resource_returned_note [dir=none,style=dotted];
9.154 + }
9.155 +
9.156 + subgraph {
9.157 + rank=same;
9.158 +
9.159 + Resource [label="Resource\n(Pager)"];
9.160 +
9.161 + FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"];
9.162 + FileOpening;
9.163 +
9.164 + FileOpening_note -> FileOpening [dir=none,style=dotted];
9.165 + }
9.166 +
9.167 + subgraph {
9.168 + rank=max;
9.169 +
9.170 + ProviderRegistry_note [shape=note,style=filled,fillcolor=gold,label="Provides\nopen files"];
9.171 + ProviderRegistry;
9.172 +
9.173 + Provider;
9.174 + Provider_note [shape=note,style=filled,fillcolor=gold,label="Represents\nopen file"];
9.175 +
9.176 + ProviderRegistry_note -> ProviderRegistry [dir=none,style=dotted];
9.177 + Provider -> Provider_note [dir=none,style=dotted];
9.178 + }
9.179 +
9.180 + /* Obtaining a resource from the registry. */
9.181 +
9.182 + Opener -> ResourceRegistry [label="get_resource"];
9.183 + ResourceRegistry -> Resource_returned [dir=none];
9.184 + Resource_returned -> Opener;
9.185 +
9.186 + /* Obtaining a provider. */
9.187 +
9.188 + ResourceRegistry -> FileOpening [label="get_fileid"];
9.189 + ResourceRegistry -> ProviderRegistry [label="get(fileid)"];
9.190 + ProviderRegistry -> Provider;
9.191 +
9.192 + /* Obtaining the resource from the provider. */
9.193 +
9.194 + ResourceRegistry -> Provider [label="make_resource"];
9.195 + Provider -> Resource [dir=none];
9.196 + Resource -> ResourceRegistry;
9.197 +}
9.198 +}}}
9.199 +
9.200 +########
9.201 +
9.202 +Where a provider does not already exist, with the file not having been opened
9.203 +already, some extra interactions occur:
9.204 +
9.205 +######## A graph showing opening mechanism details for an unopened file
9.206 +
9.207 +{{{#!graphviz
9.208 +#format svg
9.209 +#transform notugly
9.210 +digraph opening_unopened {
9.211 + node [fontsize="12.0",fontname="sans-serif",shape=box];
9.212 + edge [fontsize="12.0",fontname="sans-serif"];
9.213 + rankdir=LR;
9.214 +
9.215 + Opener;
9.216 +
9.217 + ResourceRegistry;
9.218 +
9.219 + subgraph {
9.220 + rank=same;
9.221 +
9.222 + Provider_note [shape=note,style=filled,fillcolor=gold,label="Created\nand set in\nregistry"];
9.223 + Provider;
9.224 +
9.225 + Accessor;
9.226 + PageMapper;
9.227 + PageMapper_note [shape=note,style=filled,fillcolor=gold,label="Created\nfor provider"];
9.228 +
9.229 + Provider_note -> Provider [dir=none,style=dotted];
9.230 + PageMapper -> PageMapper_note [dir=none,style=dotted];
9.231 + }
9.232 +
9.233 + subgraph {
9.234 + rank=max;
9.235 +
9.236 + ProviderRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen files"];
9.237 + ProviderRegistry;
9.238 + FileOpening;
9.239 + FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"];
9.240 +
9.241 + ProviderRegistry_note -> ProviderRegistry [dir=none,style=dotted];
9.242 + FileOpening -> FileOpening_note [dir=none,style=dotted];
9.243 + }
9.244 +
9.245 + Opener -> ResourceRegistry [dir=none,style=dashed];
9.246 +
9.247 + /* Obtaining a new provider. */
9.248 +
9.249 + ResourceRegistry -> FileOpening [label="make_accessor"];
9.250 + FileOpening -> Accessor [dir=none];
9.251 + Accessor -> PageMapper -> ResourceRegistry;
9.252 +
9.253 + ResourceRegistry -> Provider [dir=none];
9.254 + Provider -> ProviderRegistry [label="set(fileid)"];
9.255 +}
9.256 +}}}
9.257 +
9.258 +########
9.259 +
9.260 +== Notifications ==
9.261 +
9.262 +Within the filesystem access architecture, users of files may act in ways that
9.263 +may notify other users of the same file. To support such notifications, an
9.264 +interface is provided for filesystem clients to subscribe and unsubscribe to
9.265 +notifications. The notifications themselves occur when files are opened,
9.266 +modified and closed. Pipes also generate notifications when a pipe reader
9.267 +makes more space available for the writer.
9.268 +
9.269 +######## A graph showing subscription to notifications
9.270 +
9.271 +{{{#!graphviz
9.272 +#format svg
9.273 +#transform notugly
9.274 +digraph notification_subscriptions {
9.275 + node [fontsize="12.0",fontname="sans-serif",shape=box];
9.276 + edge [fontsize="12.0",fontname="sans-serif"];
9.277 + rankdir=LR;
9.278 +
9.279 + subgraph {
9.280 + rank=same;
9.281 +
9.282 + Client1 [label="Client\nprogram"];
9.283 + Client2 [label="Client\nprogram"];
9.284 + }
9.285 +
9.286 + subgraph {
9.287 + rank=same;
9.288 +
9.289 + Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Created for\nnotifications"];
9.290 + Notifier1 [label="Notifier"];
9.291 + Notifier2 [label="Notifier"];
9.292 +
9.293 + Notifier1_note -> Notifier1 -> Notifier2 [dir=none,style=dotted];
9.294 + }
9.295 +
9.296 + subgraph {
9.297 + rank=same;
9.298 +
9.299 + Resource1 [label="Resource\n(Pager)"];
9.300 + Resource2 [label="Resource\n(Pager)"];
9.301 + }
9.302 +
9.303 + subgraph {
9.304 + rank=same;
9.305 +
9.306 + Notifier1_subscribe_note [shape=note,style=filled,fillcolor=gold,label="Propagated to\nprovider"];
9.307 + Notifier1_subscribe [label="Notifier"];
9.308 + Notifier2_subscribe [label="Notifier"];
9.309 +
9.310 + Notifier1_subscribe_note -> Notifier1_subscribe -> Notifier2_subscribe [dir=none,style=dotted];
9.311 + }
9.312 +
9.313 + subgraph {
9.314 + rank=same;
9.315 +
9.316 + Provider_note [shape=note,style=filled,fillcolor=gold,label="Manages file\nsubscriptions"];
9.317 + Provider [label="Provider"];
9.318 +
9.319 + Provider_note -> Provider [dir=none,style=dotted];
9.320 + }
9.321 +
9.322 + /* Subscribing. */
9.323 +
9.324 + Client1 -> Notifier1 [dir=none];
9.325 + Notifier1 -> Resource1 [label="subscribe"];
9.326 +
9.327 + Resource1 -> Notifier1_subscribe [dir=none];
9.328 + Notifier1_subscribe -> Provider [label="subscribe"];
9.329 +
9.330 + Client2 -> Notifier2 [dir=none];
9.331 + Notifier2 -> Resource2 [label="subscribe"];
9.332 +
9.333 + Resource2 -> Notifier2_subscribe [dir=none];
9.334 + Notifier2_subscribe -> Provider [label="subscribe"];
9.335 +}
9.336 +}}}
9.337 +
9.338 +########
9.339 +
9.340 +An example of a notification scenario is given below:
9.341 +
9.342 +######## A graph showing notification
9.343 +
9.344 +{{{#!graphviz
9.345 +#format svg
9.346 +#transform notugly
9.347 +digraph notifications {
9.348 + node [fontsize="12.0",fontname="sans-serif",shape=box];
9.349 + edge [fontsize="12.0",fontname="sans-serif"];
9.350 + rankdir=LR;
9.351 +
9.352 + subgraph {
9.353 + rank=same;
9.354 +
9.355 + Client1 [label="Client\nprogram"];
9.356 + Client2 [label="Client\nprogram"];
9.357 + }
9.358 +
9.359 + subgraph {
9.360 + rank=same;
9.361 +
9.362 + Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Registered for\nnotifications"];
9.363 + Notifier1 [label="Notifier"];
9.364 +
9.365 + Resource2 [label="Resource\n(Pager)"];
9.366 + Resource2_note [shape=note,style=filled,fillcolor=gold,label="Generates\nnotification"];
9.367 +
9.368 + Notifier1_note -> Notifier1 [dir=none,style=dotted];
9.369 + Resource2 -> Resource2_note [dir=none,style=dotted];
9.370 + }
9.371 +
9.372 + subgraph {
9.373 + rank=same;
9.374 +
9.375 + Provider_note [shape=note,style=filled,fillcolor=gold,label="Propagates\nnotifications"];
9.376 + Provider [label="Provider"];
9.377 +
9.378 + Provider_note -> Provider [dir=none,style=dotted];
9.379 + }
9.380 +
9.381 + /* A notification scenario. */
9.382 +
9.383 + Client2 -> Resource2 [label="resize"];
9.384 + Resource2 -> Provider [label="notify_others"];
9.385 + Provider -> Notifier1 [label="notify"];
9.386 + Client1 -> Notifier1 [label="wait"];
9.387 +}
9.388 +}}}
9.389 +
9.390 +########
9.391 +
9.392 +Notifications provide the basis for blocking reading and writing operations,
9.393 +with pipe endpoints depending on such blocking for efficient use of pipes. The
9.394 +interactions involved when transferring data through pipes are depicted below.
9.395 +
9.396 +######## A graph showing notifications employed by pipe endpoints
9.397 +
9.398 +{{{#!graphviz
9.399 +#format svg
9.400 +#transform notugly
9.401 +digraph pipe_notifications {
9.402 + node [fontsize="12.0",fontname="sans-serif",shape=box];
9.403 + edge [fontsize="12.0",fontname="sans-serif"];
9.404 + rankdir=LR;
9.405 +
9.406 + subgraph {
9.407 + rank=min;
9.408 +
9.409 + Client1_note [shape=note,style=filled,fillcolor=gold,label="Fill pipe\nthen request\nmore space"];
9.410 + Client1 [label="Client\nprogram\n(writer)"];
9.411 + Client1_wait_note [shape=note,style=filled,fillcolor=gold,label="Waiting after\nfilling pipe"];
9.412 + Client1_wait [label="Client\nprogram\n(writer)"];
9.413 +
9.414 + Client1_note -> Client1 [dir=none,style=dotted];
9.415 + Client1_wait_note -> Client1_wait [dir=none,style=dotted];
9.416 +
9.417 + Client1 -> Client1_wait_note [dir=none,style=invis];
9.418 + }
9.419 +
9.420 + subgraph {
9.421 + rank=max;
9.422 +
9.423 + Client2_note [shape=note,style=filled,fillcolor=gold,label="Waiting for\nmore content\nbefore reading"];
9.424 + Client2 [label="Client\nprogram\n(reader)"];
9.425 + Client2_read_note [shape=note,style=filled,fillcolor=gold,label="Empty pipe\nthen request\nmore content"];
9.426 + Client2_read [label="Client\nprogram\n(reader)"];
9.427 +
9.428 + Client2_note -> Client2 [dir=none,style=dotted];
9.429 + Client2_read_note -> Client2_read [dir=none,style=dotted];
9.430 + }
9.431 +
9.432 + subgraph {
9.433 + rank=same;
9.434 +
9.435 + Notifier1 [label="Notifier"];
9.436 + Resource1 [label="Resource\n(PipePager)"];
9.437 + }
9.438 +
9.439 + subgraph {
9.440 + rank=same;
9.441 +
9.442 + Notifier2 [label="Notifier"];
9.443 + Resource2 [label="Resource\n(PipePager)"];
9.444 + }
9.445 +
9.446 + subgraph {
9.447 + rank=same;
9.448 +
9.449 + PipePaging [label="Provider\n(PipePaging)"];
9.450 + PipePaging_space [label="Provider\n(PipePaging)"];
9.451 + }
9.452 +
9.453 + /* Making content available. */
9.454 +
9.455 + Client1 -> Resource1 [label="next_region"];
9.456 + Resource1 -> PipePaging [label="add_region"];
9.457 + PipePaging -> Notifier2 [label="notify"];
9.458 + Client2 -> Notifier2 [label="wait"];
9.459 +
9.460 + /* Making space available. */
9.461 +
9.462 + Client2_read -> Resource2 [label="next_region"];
9.463 + Resource2 -> PipePaging_space [label="next_region"];
9.464 + PipePaging_space -> Notifier1 [label="notify"];
9.465 + Client1_wait -> Notifier1 [label="wait"];
9.466 +}
9.467 +}}}
9.468 +
9.469 +########
9.470 +
9.471 +== Closing Files ==
9.472 +
9.473 +Files are closed when client programs release their references to the resource
9.474 +capabilities used to access files. The mechanism by which this is done
9.475 +involves the registration of an IRQ object that is bound to the same thread as
9.476 +the one used by resources to service file access requests. This IRQ object is
9.477 +associated with the IPC gate through which such requests occur, and the IRQ
9.478 +object is configured to deliver an interrupt message when the final reference
9.479 +to the IPC gate has been released.
9.480 +
9.481 +When a client program terminates, its references to capabilities should be
9.482 +released, and this should cause a reference counter associated with the IPC
9.483 +gate to decrement. Upon the loss of the final reference and the delivery of
9.484 +the interrupt, the server framework will call a `close` method on the
9.485 +`Resource` object concerned, this implementing the
9.486 +[[ServerLibrary#Accountable|`Accountable`]] interface.
9.487 +
9.488 +######## A graph showing the closing mechanism
9.489 +
9.490 +{{{#!graphviz
9.491 +#format svg
9.492 +#transform notugly
9.493 +digraph closing {
9.494 + node [fontsize="12.0",fontname="sans-serif",shape=box];
9.495 + edge [fontsize="12.0",fontname="sans-serif"];
9.496 + rankdir=LR;
9.497 +
9.498 + Client [label="Client\nprogram"];
9.499 +
9.500 + subgraph {
9.501 + rank=same;
9.502 +
9.503 + Gate_note [shape=note,style=filled,fillcolor=gold,label="Actual\nendpoint"];
9.504 + Gate [label="IPC gate",shape="octagon"];
9.505 + IRQ [shape="triangle"];
9.506 + ResourceServer;
9.507 + ResourceServer_note [shape=note,style=filled,fillcolor=gold,label="Handles\nrequests"];
9.508 +
9.509 + Gate_note -> Gate [dir=none,style=dotted];
9.510 + ResourceServer -> ResourceServer_note [dir=none,style=dotted];
9.511 + }
9.512 +
9.513 + Resource [label="Resource\n(Pager)"];
9.514 +
9.515 + Provider;
9.516 +
9.517 + ProviderRegistry;
9.518 +
9.519 + Client -> Gate [style=dashed,label="(release)"];
9.520 + Gate -> IRQ -> ResourceServer;
9.521 + ResourceServer -> Resource [label="close"];
9.522 + Resource -> Provider [label="notify_others\nunsubscribe"];
9.523 + Resource -> ProviderRegistry [label="detach"];
9.524 +}
9.525 +}}}
9.526 +
9.527 +########
9.528 +
9.529 +As a consequence of closing a file, an `unsubscribe` operation performed on
9.530 +the `Provider` should cause any `Notifier` objects associated with the
9.531 +`Resource` object to be released. Meanwhile, the `ResourceServer` will discard
9.532 +the `Resource` object before the server thread terminates.
9.533 +
9.534 +== Removing Files ==
9.535 +
9.536 +Unix filesystem semantics typically allow a file to be "unlinked" while still
9.537 +being accessed by a program, with accesses still being directed to the file,
9.538 +but with the file being removed from a directory and potentially being
9.539 +replaced by another file. To support this, a mechanism is provided to defer
9.540 +any removal of an open file.
9.541 +
9.542 +######## A graph showing the removal mechanism
9.543 +
9.544 +{{{#!graphviz
9.545 +#format svg
9.546 +#transform notugly
9.547 +digraph removing {
9.548 + node [fontsize="12.0",fontname="sans-serif",shape=box];
9.549 + edge [fontsize="12.0",fontname="sans-serif"];
9.550 + rankdir=LR;
9.551 +
9.552 + subgraph {
9.553 + rank=same;
9.554 +
9.555 + Client1_note [shape=note,style=filled,fillcolor=gold,label="Removing\nopen file"];
9.556 + Client1 [label="Client\nprogram"];
9.557 + Client2 [label="Client\nprogram"];
9.558 + Client2_note [shape=note,style=filled,fillcolor=gold,label="Closes\nopen file"];
9.559 +
9.560 + Client1_note -> Client1 [dir=none,style=dotted];
9.561 + Client2 -> Client2_note [dir=none,style=dotted];
9.562 +
9.563 + Client1 -> Client2 [dir=none,style=invis];
9.564 + }
9.565 +
9.566 + subgraph {
9.567 + rank=same;
9.568 +
9.569 + Resource [label="Resource\n(Pager)"];
9.570 + Opener;
9.571 + }
9.572 +
9.573 + subgraph {
9.574 + rank=same;
9.575 +
9.576 + Provider1 [label="Provider"];
9.577 + Provider1_note [shape=note,style=filled,fillcolor=gold,label="Maintains\nremoval\nstate"];
9.578 + Provider2 [label="Provider"];
9.579 +
9.580 + Provider1 -> Provider1_note -> Provider2 [dir=none,style=dotted];
9.581 + }
9.582 +
9.583 + ProviderRegistry1 [label="ProviderRegistry"];
9.584 + ProviderRegistry2 [label="ProviderRegistry"];
9.585 +
9.586 + subgraph {
9.587 + rank=same;
9.588 +
9.589 + FileOpening;
9.590 + Accessor_note [shape=note,style=filled,fillcolor=gold,label="Performing\nfilesystem\noperations"];
9.591 + Accessor;
9.592 +
9.593 + FileOpening -> Accessor_note -> Accessor [dir=none,style=dotted];
9.594 + }
9.595 +
9.596 + /* Removing the file while it remains open. */
9.597 +
9.598 + Client1 -> Opener [label="remove\n(via context)"];
9.599 + Opener -> ResourceRegistry [label="remove_provider"];
9.600 + ResourceRegistry -> FileOpening [label="get_fileid\nunlink_object"];
9.601 + ResourceRegistry -> ProviderRegistry1 [label="get(fileid)"];
9.602 + ResourceRegistry -> Provider1 [label="remove_pending"];
9.603 +
9.604 + /* File closure and deferred removal. */
9.605 +
9.606 + Client2 -> Resource [label="close"];
9.607 + Resource -> Provider2 [label="notify_others\nunsubscribe"];
9.608 + Resource -> ProviderRegistry2 [label="detach"];
9.609 + ProviderRegistry2 -> Provider2 [label="remove"];
9.610 + Provider2 -> Accessor [label="remove"];
9.611 +}
9.612 +}}}
9.613 +
9.614 +########
10.1 --- a/docs/wiki/Filesystems Sun Jun 12 17:10:30 2022 +0200
10.2 +++ b/docs/wiki/Filesystems Wed Aug 10 00:25:44 2022 +0200
10.3 @@ -5,6 +5,15 @@
10.4
10.5 == Topics ==
10.6
10.7 - * [[Components]] and [[Mechanisms]]
10.8 - * [[ClientLibrary|Client Library]]
10.9 + * [[ClientLibrary|Client Library]] - convenience functions and structures to
10.10 + access filesystem objects
10.11 + * [[Components]] - server objects exposed at the system level that support
10.12 + filesystem access
10.13 + * [[FilesystemAccess|Filesystem Access]] - mechanisms within filesystem
10.14 + servers to manage filesystem resources and content
10.15 + * [[Paging]] - the mechanism by which filesystem content is provided for use
10.16 + by client programs
10.17 + * [[ProgramLoading|Program Loading]] - the mechanism by which programs are loaded
10.18 + * [[ServerLibrary|Server Library]] - abstractions to expose and manage access
10.19 + to filesystem objects
10.20 * [[Users]]
11.1 --- a/docs/wiki/Mechanisms Sun Jun 12 17:10:30 2022 +0200
11.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
11.3 @@ -1,299 +0,0 @@
11.4 -= Mechanisms =
11.5 -
11.6 -Within the filesystem server library, a number of different abstractions and
11.7 -mechanisms are employed to provide access to filesystem objects.
11.8 -
11.9 -<<TableOfContents(2,3)>>
11.10 -
11.11 -The abstractions or components used in the library are organised as follows.
11.12 -
11.13 -######## A graph showing the relationships between library components
11.14 -
11.15 -{{{#!graphviz
11.16 -#format svg
11.17 -#transform notugly
11.18 -digraph components {
11.19 - node [fontsize="12.0",fontname="sans-serif",shape=box];
11.20 - edge [fontsize="12.0",fontname="sans-serif"];
11.21 - rankdir=LR;
11.22 -
11.23 - subgraph {
11.24 - rank=same;
11.25 -
11.26 - Resource -> DirectoryResource -> FilePager
11.27 - [dir=none,style=dotted];
11.28 - }
11.29 -
11.30 - subgraph {
11.31 - rank=same;
11.32 -
11.33 - Provider -> DirectoryProvider -> FileProvider
11.34 - [dir=none,style=dotted];
11.35 - }
11.36 -
11.37 - subgraph {
11.38 - rank=same;
11.39 -
11.40 - Accessor -> Ext2FileAccessor
11.41 - [dir=none,style=dotted];
11.42 - }
11.43 -
11.44 - subgraph {
11.45 - rank=same;
11.46 -
11.47 - DirectoryAccessor -> Ext2DirectoryAccessor
11.48 - [dir=none,style=dotted];
11.49 - }
11.50 -
11.51 - subgraph {
11.52 - node [shape=ellipse];
11.53 - rank=same;
11.54 -
11.55 - Directory [label="dir"];
11.56 - File [label="dir/file"];
11.57 - }
11.58 -
11.59 - DirectoryResource -> DirectoryProvider -> Ext2DirectoryAccessor -> Directory;
11.60 - FilePager -> FileProvider -> Ext2FileAccessor -> File;
11.61 -}
11.62 -}}}
11.63 -
11.64 -########
11.65 -
11.66 -This document uses C-style interface syntax since the components operating
11.67 -within the described mechanisms will themselves be described using such
11.68 -syntax.
11.69 -
11.70 -== Accountable ==
11.71 -
11.72 -This interface provides the following operations:
11.73 -
11.74 -{{{
11.75 -void attach()
11.76 -unsigned int detach()
11.77 -}}}
11.78 -
11.79 -Its purpose is to provide reference counting for components, with the `attach`
11.80 -operation incrementing the number of users of a component, and with the
11.81 -`detach` operation decrementing the number of users and returning the
11.82 -resulting number of users. When components no longer have any attached users,
11.83 -they may perform operations to tidy up after themselves and permit their
11.84 -deallocation.
11.85 -
11.86 -== Accessors ==
11.87 -
11.88 -Accessors provide the means of accessing filesystem object data and metadata.
11.89 -Conceptually, files and directories are both exposed by accessors, although
11.90 -the interfaces and mechanisms may differ between these types of objects.
11.91 -
11.92 -=== Directory Accessors ===
11.93 -
11.94 -Currently, directory accessors provide support for traversing directory
11.95 -listings, obtaining the relevant filesystem metadata using the underlying
11.96 -filesystem access library.
11.97 -
11.98 -=== File Accessors ===
11.99 -
11.100 -File content is accessed through an interface with the following operations:
11.101 -
11.102 -{{{
11.103 -void close()
11.104 -void fill(Flexpage *flexpage)
11.105 -void flush(Flexpage *flexpage)
11.106 -offset_t get_size()
11.107 -void set_size(offset_t size)
11.108 -}}}
11.109 -
11.110 -The operations need to be supported with actual filesystem operations. For
11.111 -example, ext2-based filesystems employ a specific abstraction which invokes
11.112 -library functions provided by the `libext2fs` package.
11.113 -
11.114 -== Providers ==
11.115 -
11.116 -Providers encapsulate the essential functionality for accessing filesystem
11.117 -objects. Implementing the `Accountable` interface, they are shared by
11.118 -resources and discarded when no resources are using them.
11.119 -
11.120 -The following operations are supported by providers:
11.121 -
11.122 -{{{
11.123 -ProviderRegistry *registry()
11.124 -long make_resource(offset_t *size, object_flags_t *object_flags, Resource **resource)
11.125 -bool removal_pending()
11.126 -void remove()
11.127 -void remove_pending(bool remove)
11.128 -}}}
11.129 -
11.130 -Providers are associated with filesystem objects in a registry which can be
11.131 -obtained from each provider using the `registry` operation.
11.132 -
11.133 -Providers also support the creation of resources through which each user of a
11.134 -provider exercises its use of that provider. The `make_resource` operation
11.135 -performs the creation and returns size, flags and resource instance details.
11.136 -
11.137 -The removal of providers can be directed using the `remove_pending` and
11.138 -`remove` operations. Where `remove_pending` has been called with a true value
11.139 -as its parameter, the `removal_pending` operation will also return a true
11.140 -value, and upon the provider being discarded, the `remove` operation will be
11.141 -invoked. The `remove` operation performs the appropriate underlying operation
11.142 -to remove the object being provided.
11.143 -
11.144 -Typically, removal of providers is managed by the provider registry when
11.145 -resources are closed and detached from providers.
11.146 -
11.147 -######## A graph showing the removal mechanism
11.148 -
11.149 -{{{#!graphviz
11.150 -#format svg
11.151 -#transform notugly
11.152 -digraph provider_removal {
11.153 - node [fontsize="12.0",fontname="sans-serif",shape=box];
11.154 - edge [fontsize="12.0",fontname="sans-serif"];
11.155 - rankdir=LR;
11.156 -
11.157 - ResourceServer -> Resource [label="close"];
11.158 - Resource -> ProviderRegistry [label="detach"];
11.159 - ProviderRegistry -> Provider [label="remove"];
11.160 -}
11.161 -}}}
11.162 -
11.163 -########
11.164 -
11.165 -== Resources ==
11.166 -
11.167 -Resources are objects accessed by clients that support a basic level of
11.168 -accounting and management.
11.169 -
11.170 -The base interface of a resource is as follows:
11.171 -
11.172 -{{{
11.173 -void activate()
11.174 -void close()
11.175 -}}}
11.176 -
11.177 -Activation of a resource is an optional operation that performs any
11.178 -initialisation before a resource is made available to its user.
11.179 -
11.180 -In practice, other operations are required to make resources useful.
11.181 -
11.182 -In some cases, resources provide the mechanism by which each user of a
11.183 -filesystem object may access that object independently. They would then
11.184 -effectively provide a session in which accesses can occur.
11.185 -
11.186 -=== Directory Resources ===
11.187 -
11.188 -Directory resources primarily expose the contents of directories in the
11.189 -filesystem to a user. They employ directory accessors which concern themselves
11.190 -with the actual filesystem content.
11.191 -
11.192 -[[Components#Directories|Directory components]] are provided using directory
11.193 -resources.
11.194 -
11.195 -=== Pagers or File Resources ===
11.196 -
11.197 -Pagers are resources that support dataspace access operations, thus allowing
11.198 -the resources to expose filesystem content in mapped memory regions to a
11.199 -particular user of the object providing the content.
11.200 -
11.201 -[[Components#Files|File components]] and [[Components#Pipes|pipe components]]
11.202 -are provided using pagers.
11.203 -
11.204 -=== Filesystem Resources ===
11.205 -
11.206 -Filesystem resources provide the entry point for access to a filesystem by
11.207 -other components or programs. Since filesystems often enforce identity-based
11.208 -access controls, a filesystem resource will typically support the
11.209 -`open_for_user` operation in various forms, with the result of this operation
11.210 -being the instantiation of an `OpenerResource` configured for the indicated
11.211 -user identity.
11.212 -
11.213 -== Registries ==
11.214 -
11.215 -The basic mechanism for obtaining a resource involves a registry, as
11.216 -illustrated by the following diagram.
11.217 -
11.218 -######## A graph showing the use of a registry in obtaining resources
11.219 -
11.220 -{{{#!graphviz
11.221 -#format svg
11.222 -#transform notugly
11.223 -digraph registry {
11.224 - node [fontsize="12.0",fontname="sans-serif",shape=box];
11.225 - edge [fontsize="12.0",fontname="sans-serif"];
11.226 - rankdir=LR;
11.227 -
11.228 - subgraph {
11.229 - node [label="OpenerContextResource"];
11.230 - rank=same;
11.231 -
11.232 - OpenerContextResource1 -> OpenerContextResource2 [dir=none,style=dotted];
11.233 - }
11.234 -
11.235 - subgraph {
11.236 - node [label="OpenerResource"];
11.237 - rank=same;
11.238 -
11.239 - OpenerResource1 -> OpenerResource2 [dir=none,style=dotted];
11.240 - }
11.241 -
11.242 - subgraph {
11.243 - rank=same;
11.244 -
11.245 - ResourceRegistry -> Resource;
11.246 - }
11.247 -
11.248 - subgraph {
11.249 - rank=same;
11.250 -
11.251 - ProviderRegistry -> Provider;
11.252 - }
11.253 -
11.254 - OpenerContextResource1 -> OpenerResource1 [label="open"];
11.255 - OpenerResource1 -> ResourceRegistry [label="get_resource"];
11.256 - ResourceRegistry -> ProviderRegistry [label="get/set"];
11.257 -
11.258 - Provider -> Resource -> OpenerResource2 -> OpenerContextResource2;
11.259 -}
11.260 -}}}
11.261 -
11.262 -########
11.263 -
11.264 -The `ResourceRegistry` coordinates access to filesystem resources and, through
11.265 -synchronisation, prevents conflicting operations from occurring concurrently.
11.266 -For example, a removal operation on a file may not be allowed to occur while
11.267 -an opening operation is in progress.
11.268 -
11.269 -To achieve this, a common lock is employed to serialise access, with any
11.270 -underlying filesystem operations being initiated from the registry while the
11.271 -lock is held. An object providing the `FileOpening` interface for a filesystem
11.272 -provides such operations, and the following interaction pattern is thereby
11.273 -employed:
11.274 -
11.275 -######## A graph showing the registry coordinating filesystem operations
11.276 -
11.277 -{{{#!graphviz
11.278 -#format svg
11.279 -#transform notugly
11.280 -digraph registry_operations {
11.281 - node [fontsize="12.0",fontname="sans-serif",shape=box];
11.282 - edge [fontsize="12.0",fontname="sans-serif"];
11.283 - rankdir=LR;
11.284 -
11.285 - OpenerContextResource -> OpenerResource -> ResourceRegistry -> FileOpening;
11.286 -}
11.287 -}}}
11.288 -
11.289 -########
11.290 -
11.291 -Since the `ResourceRegistry` functionality is generic, it could be specialised
11.292 -for each filesystem or be configured with an appropriate reference to a
11.293 -`FileOpening` object. The `OpenerResource` would then be generic, invoking the
11.294 -registry which would, in turn, invoke the opening object.
11.295 -
11.296 -However, the chosen approach is to permit `OpenerResource` objects to
11.297 -implement the `FileOpening` interface for each filesystem, meaning that the
11.298 -`ResourceRegistry` will end up being called by the opener and then invoking
11.299 -the opener in return. This is slightly more convenient than the alternative
11.300 -since the opener can be configured with a given user identity, and such
11.301 -identity details will ultimately be employed when accessing the underlying
11.302 -filesystem itself.
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/docs/wiki/Paging Wed Aug 10 00:25:44 2022 +0200
12.3 @@ -0,0 +1,336 @@
12.4 += Paging =
12.5 +
12.6 +Within filesystem servers, a number of abstractions are combined to support
12.7 +[[FilesystemAccess|access to filesystem content]] through paging: the delivery
12.8 +of content to clients in mapped memory. The general mechanism used to support
12.9 +paging is depicted below.
12.10 +
12.11 +######## A graph showing the general paging mechanism
12.12 +
12.13 +{{{#!graphviz
12.14 +#format svg
12.15 +#transform notugly
12.16 +digraph paging {
12.17 + node [fontsize="12.0",fontname="sans-serif",shape=box];
12.18 + edge [fontsize="12.0",fontname="sans-serif"];
12.19 + rankdir=LR;
12.20 +
12.21 + subgraph {
12.22 + rank=same;
12.23 +
12.24 + Pager_note [shape=note,style=filled,fillcolor=gold,label="Provides\nfilesystem\ncontent"];
12.25 + Pager;
12.26 +
12.27 + Pager_note -> Pager [dir=none,style=dotted];
12.28 + }
12.29 +
12.30 + subgraph {
12.31 + rank=same;
12.32 +
12.33 + PageMapper_note [shape=note,style=filled,fillcolor=gold,label="Provides\npopulated\nfile pages"];
12.34 + PageMapper;
12.35 +
12.36 + PageMapper_note -> PageMapper [dir=none,style=dotted];
12.37 + }
12.38 +
12.39 + subgraph {
12.40 + rank=same;
12.41 +
12.42 + Accessor_note [shape=note,style=filled,fillcolor=gold,label="Populates\nfile pages"];
12.43 + Accessor;
12.44 +
12.45 + Accessor_note -> Accessor [dir=none,style=dotted];
12.46 + }
12.47 +
12.48 + AccessMap [shape=record,label="<head> AccessMap |
12.49 + { offset-0 |<fp0> flexpage-0 } | ... |
12.50 + { offset-n |<fpn> flexpage-n } | ..."];
12.51 +
12.52 + subgraph {
12.53 + rank=same;
12.54 +
12.55 + Pages_note [shape=note,style=filled,fillcolor=gold,label="Provides\nmemory\npages"];
12.56 + Pages;
12.57 +
12.58 + Pages_note -> Pages [dir=none,style=dotted];
12.59 + }
12.60 +
12.61 + PageQueue [shape=record,label="<head> PageQueue |
12.62 + { owner-0 |<fp0> flexpage-0 } | ... |
12.63 + { owner-N |<fpN> flexpage-N } | <end> ..."];
12.64 +
12.65 + Flexpage_offset_n [shape=record,label="<head> Flexpage |
12.66 + offset | size |<r> region"];
12.67 +
12.68 + subgraph {
12.69 + rank=same;
12.70 +
12.71 + Memory_note [shape=note,style=filled,fillcolor=gold,label="Allocates\nmemory\nregions"];
12.72 + Memory;
12.73 +
12.74 + Memory_note -> Memory [dir=none,style=dotted];
12.75 + }
12.76 +
12.77 + Region;
12.78 +
12.79 + /* Relationships. */
12.80 +
12.81 + PageMapper -> Accessor;
12.82 + PageMapper -> AccessMap:head;
12.83 + Pager -> PageMapper -> Pages;
12.84 + Pages -> Memory;
12.85 + Pages -> PageQueue:head;
12.86 + AccessMap:fpn -> Flexpage_offset_n:head;
12.87 + PageQueue:fpN -> Flexpage_offset_n:head;
12.88 + Flexpage_offset_n:r -> Region;
12.89 +}
12.90 +}}}
12.91 +
12.92 +########
12.93 +
12.94 +A [[ServerLibrary#Pager|`Pager`]], being a resource that provides filesystem
12.95 +content to clients for a particular file, requests pages from the
12.96 +`PageMapper`, itself having the role of supplying populated pages of content
12.97 +from the given file. The `PageMapper` relies on the `AccessMap` to discover
12.98 +existing pages for any accessed region of a file, involving the `Pages` object
12.99 +(or page collection) to obtain new memory pages where existing pages are not
12.100 +available or are no longer valid. It also requests the population of such
12.101 +pages through use of the associated `Accessor` for the file concerned.
12.102 +
12.103 +== Obtaining and Queuing Pages ==
12.104 +
12.105 +The `Pages` object may either obtain new memory pages from a `Memory` object
12.106 +or reclaim (or recycle) existing pages from a `PageQueue`, this recording all
12.107 +pages that have been populated and supplied to clients. Since it may be
12.108 +desirable to limit the number of pages employed to satisfy file access
12.109 +operations, the `PageQueue` provides a kind of lending mechanism: pages are
12.110 +issued to clients and then added to the end of the queue; where no new page
12.111 +can be supplied by a `Memory` object, the issued page at the head of the queue
12.112 +is obtained for recycling; ultimately, an issued page will remain valid for
12.113 +its user (the client accessing its contents) until all pages in front of it in
12.114 +the queue are themselves recycled and it is then removed from the queue for
12.115 +recycling.
12.116 +
12.117 +== Satisfying Requests for Pages ==
12.118 +
12.119 +The general procedure for satisfying requests for pages is as follows:
12.120 +
12.121 + 1. Attempt to find an existing page for the affected file region.
12.122 + 1. With an existing page, attempt to reserve the page for issuing.
12.123 + 1. Without an existing or reserved page, obtain a fresh page for populating.
12.124 + 1. Queue the page for eventual reuse.
12.125 +
12.126 +Since many files are likely to be in use, and since a fixed amount of memory
12.127 +may be shared to provide access to file content, the interaction between
12.128 +different `PageMapper` objects, operating on behalf of different files, must
12.129 +be taken into consideration. The following diagram depicts the principal
12.130 +mechanisms involved in securing access to pages so as to provide access to
12.131 +file content.
12.132 +
12.133 +######## A graph showing concurrency considerations
12.134 +
12.135 +{{{#!graphviz
12.136 +#format svg
12.137 +#transform notugly
12.138 +digraph paging_concurrency {
12.139 + node [fontsize="12.0",fontname="sans-serif",shape=box];
12.140 + edge [fontsize="12.0",fontname="sans-serif"];
12.141 + rankdir=LR;
12.142 +
12.143 + /* First page mapper activities. */
12.144 +
12.145 + subgraph {
12.146 + rank=same;
12.147 +
12.148 + PageMapper1_note [shape=note,style=filled,fillcolor=gold,label="Find\nflexpage"];
12.149 + PageMapper1 [label="PageMapper"];
12.150 +
12.151 + Accessor1 [label="Accessor"];
12.152 +
12.153 + PageMapper1_reserve_note [shape=note,style=filled,fillcolor=gold,label="Reserve\nflexpage"];
12.154 + PageMapper1_reserve [label="PageMapper"];
12.155 +
12.156 + PageMapper1_queue_note [shape=note,style=filled,fillcolor=gold,label="Queue\nflexpage"];
12.157 + PageMapper1_queue [label="PageMapper"];
12.158 +
12.159 + PageMapper1_note -> PageMapper1 [dir=none,style=dotted];
12.160 + PageMapper1_reserve_note -> PageMapper1_reserve [dir=none,style=dotted];
12.161 + PageMapper1_queue_note -> PageMapper1_queue [dir=none,style=dotted];
12.162 + }
12.163 +
12.164 + /* Access map usage and flexpage acquisition. */
12.165 +
12.166 + subgraph {
12.167 + rank=same;
12.168 +
12.169 + AccessMap_note [shape=note,style=filled,fillcolor=gold,label="Provides\nflexpages\ntentatively"];
12.170 + AccessMap1 [label="AccessMap"];
12.171 +
12.172 + Flexpage1 [label="Flexpage",shape=note,style=dashed];
12.173 + Flexpage1_note [shape=note,style=filled,fillcolor=gold,label="Needs reservation\nif found\nby mapper"];
12.174 +
12.175 + Flexpage1_reserve [label="Flexpage",shape=note,style=dashed];
12.176 + Flexpage1_reserved [label="Flexpage",shape=note];
12.177 + Flexpage1_reserved_note [shape=note,style=filled,fillcolor=gold,label="Claimed if\nstill available"];
12.178 +
12.179 + Flexpage1_queue [label="Flexpage",shape=note];
12.180 +
12.181 + AccessMap_note -> AccessMap1 [dir=none,style=dotted];
12.182 + Flexpage1_note -> Flexpage1_reserve [dir=none,style=dotted];
12.183 + Flexpage1_reserved -> Flexpage1_reserved_note [dir=none,style=dotted];
12.184 +
12.185 + Flexpage1_reserve -> Flexpage1_reserved [dir=none,style=invis];
12.186 + }
12.187 +
12.188 + subgraph {
12.189 + rank=same;
12.190 +
12.191 + PageQueue_note [shape=note,style=filled,fillcolor=gold,label="Provides\nflexpages\ndefinitively"];
12.192 + PageQueue [label="PageQueue"];
12.193 + Flexpage [shape=note];
12.194 + Pages [label="Pages"];
12.195 + Pages_note [shape=note,style=filled,fillcolor=gold,label="Reclaim and\nrecycle\nflexpage"];
12.196 +
12.197 + PageQueue_reserve_note [shape=note,style=filled,fillcolor=gold,label="Provides\nreserved\nflexpage"];
12.198 + PageQueue_reserve [label="PageQueue"];
12.199 + Flexpage_reserve [label="Flexpage",shape=note];
12.200 + Pages_reserve [label="Pages"];
12.201 + Pages_reserve_note [shape=note,style=filled,fillcolor=gold,label="Reserve\nflexpage\nif available"];
12.202 +
12.203 + Pages_queue_note [shape=note,style=filled,fillcolor=gold,label="Queues\nissued\nflexpage"];
12.204 + Pages_queue [label="Pages"];
12.205 + Flexpage_queued [label="Flexpage",shape=note];
12.206 + PageQueue_queued [label="PageQueue"];
12.207 +
12.208 + PageQueue_note -> PageQueue [dir=none,style=dotted];
12.209 + Pages -> Pages_note [dir=none,style=dotted];
12.210 + PageQueue_reserve_note -> PageQueue_reserve [dir=none,style=dotted];
12.211 + Pages_reserve -> Pages_reserve_note [dir=none,style=dotted];
12.212 + Pages_queue_note -> Pages_queue [dir=none,style=dotted];
12.213 +
12.214 + Pages_note -> PageQueue_reserve_note [dir=none,style=invis];
12.215 + Pages_reserve_note -> Pages_queue_note [dir=none,style=invis];
12.216 + }
12.217 +
12.218 + subgraph {
12.219 + rank=same;
12.220 +
12.221 + Flexpage2 [label="Flexpage",shape=note];
12.222 + Flexpage2_note [shape=note,style=filled,fillcolor=gold,label="Reserved\nwhen obtained"];
12.223 +
12.224 + Flexpage2_reserved [label="Flexpage",shape=note];
12.225 +
12.226 + AccessMap2 [label="AccessMap"];
12.227 + AccessMap2_note [shape=note,style=filled,fillcolor=gold,label="Records\nreserved\nflexpage"];
12.228 +
12.229 + Flexpage2_queue [label="Flexpage",shape=note];
12.230 +
12.231 + Flexpage2_note -> Flexpage2 [dir=none,style=dotted];
12.232 + AccessMap2 -> AccessMap2_note [dir=none,style=dotted];
12.233 +
12.234 + Flexpage2 -> Flexpage2_reserved [dir=none,style=invis];
12.235 + }
12.236 +
12.237 + /* Second page mapper activities. */
12.238 +
12.239 + subgraph {
12.240 + rank=same;
12.241 +
12.242 + PageMapper2_note [shape=note,style=filled,fillcolor=gold,label="Obtain\nflexpage"];
12.243 + PageMapper2 [label="PageMapper"];
12.244 +
12.245 + Accessor2 [label="Accessor"];
12.246 +
12.247 + PageMapper2_record_note [shape=note,style=filled,fillcolor=gold,label="Record\nflexpage"];
12.248 + PageMapper2_record [label="PageMapper"];
12.249 +
12.250 + PageMapper2_queue_note [shape=note,style=filled,fillcolor=gold,label="Queue\nflexpage"];
12.251 + PageMapper2_queue [label="PageMapper"];
12.252 +
12.253 + PageMapper2_note -> PageMapper2 [dir=none,style=dotted];
12.254 + PageMapper2_record_note -> PageMapper2_record [dir=none,style=dotted];
12.255 + PageMapper2_queue_note -> PageMapper2_queue [dir=none,style=dotted];
12.256 + }
12.257 +
12.258 + /* First pager dataflow. */
12.259 +
12.260 + PageMapper1 -> AccessMap1 [label="find"];
12.261 + AccessMap1 -> Flexpage1 [dir=none];
12.262 + Flexpage1 -> PageMapper1;
12.263 +
12.264 + PageMapper1_reserve -> Flexpage1_reserve [dir=none];
12.265 + Flexpage1_reserve -> Pages_reserve [label="reserve"];
12.266 + Pages_reserve -> Flexpage1_reserved [dir=none];
12.267 + Flexpage1_reserved -> PageMapper1_reserve;
12.268 +
12.269 + PageMapper1_queue -> Flexpage1_queue [dir=none];
12.270 + Flexpage1_queue -> Pages_queue [label="queue"];
12.271 +
12.272 + /* Flexpage queuing. */
12.273 +
12.274 + Pages_queue -> Flexpage_queued [dir=none];
12.275 + Flexpage_queued -> PageQueue_queued;
12.276 +
12.277 + /* Flexpage retrieval from the queue. */
12.278 +
12.279 + PageQueue -> Flexpage [color="red",dir=none];
12.280 + Flexpage -> Pages [color="red"];
12.281 +
12.282 + PageQueue_reserve -> Flexpage_reserve [dir=none];
12.283 + Flexpage_reserve -> Pages_reserve;
12.284 +
12.285 + /* Flexpage removal from the access map. */
12.286 +
12.287 + Pages -> AccessMap1 [color="red",label="remove\n(via PageMapper)"];
12.288 + AccessMap1 -> PageMapper1 [color="red",label="flush"];
12.289 + PageMapper1 -> Accessor1 [color="red",label="flush"];
12.290 +
12.291 + /* Second pager dataflow. */
12.292 +
12.293 + PageMapper2 -> Pages [color="red",label="flexpage"];
12.294 + Pages -> Flexpage2 [color="red",dir=none];
12.295 + Flexpage2 -> PageMapper2 [color="red"];
12.296 + PageMapper2 -> Accessor2 [label="fill"];
12.297 +
12.298 + PageMapper2_record -> Flexpage2_reserved [dir=none,label="insert"];
12.299 + Flexpage2_reserved -> AccessMap2;
12.300 +
12.301 + PageMapper2_queue -> Flexpage2_queue [dir=none];
12.302 + Flexpage2_queue -> Pages_queue [label="queue"];
12.303 +}
12.304 +}}}
12.305 +
12.306 +########
12.307 +
12.308 +== Reclaiming and Recycling Pages ==
12.309 +
12.310 +When a `PageMapper` requests a page from the `Pages` object and when the
12.311 +`Pages` object needs to reclaim such a previously issued page, the page
12.312 +obtained from the head of the queue is removed from the `AccessMap` employed
12.313 +by the `PageMapper` that currently owns it. The "owner" of such a page is
12.314 +employing the page to satisfy requests for content in a region of a particular
12.315 +file. If modified, the page's contents may be flushed to the underlying file
12.316 +when it is removed from the owner. As a consequence of its removal, the
12.317 +`AccessMap` will no longer be able to offer this page to satisfy a request for
12.318 +data in the affected region to its `PageMapper`. A reclaimed page is then
12.319 +returned to the `PageMapper` requiring it, and since the page will no longer
12.320 +reside in the `PageQueue`, it will be exclusively available for that
12.321 +`PageMapper`, being populated with data from the underlying file and then
12.322 +issued to its client.
12.323 +
12.324 +== Reserving Available Pages ==
12.325 +
12.326 +When an `AccessMap` is able to satisfy a request for a page providing access
12.327 +to a region in a particular file, the `PageMapper` must secure exclusive
12.328 +access to that page. Otherwise, the possibility exists that the page will be
12.329 +reclaimed and recycled concurrently by another `PageMapper`. Thus, the
12.330 +`PageMapper` must request that the page be reserved by the `Pages` object
12.331 +which in turn removes the page from the `PageQueue`. Since no other party can
12.332 +now obtain the page independently, it can be issued safely.
12.333 +
12.334 +== Queuing Issued Pages ==
12.335 +
12.336 +Once a page has been issued to a client by the `Pager`, regardless of how it
12.337 +was obtained, it must be made available for future reuse. This is achieved by
12.338 +the `PageMapper` requesting the queuing of the page, with it being added to
12.339 +the end of the `PageQueue`.
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/docs/wiki/ProgramLoading Wed Aug 10 00:25:44 2022 +0200
13.3 @@ -0,0 +1,236 @@
13.4 += Program Loading =
13.5 +
13.6 +The provision of [[Paging|paging]] of file content leads to the possibility of
13.7 +demand paging for programs, enabling them to be loaded into memory dynamically
13.8 +and to have only the active portions of those programs resident. To achieve
13.9 +this, programs must be appropriately initialised in new tasks, with a page
13.10 +fault handler configured to provide program file content whenever a region of
13.11 +the program payload is encountered that is not currently resident in memory.
13.12 +
13.13 +== Internal Page Fault Handlers ==
13.14 +
13.15 +When satisfying page faults for a task, one approach involves situating the
13.16 +page fault handler within the task itself, this managing the available memory
13.17 +regions and employing receive windows when requesting memory pages.
13.18 +
13.19 +The general arrangement involving such internal page fault handlers for a
13.20 +program in a task is as follows:
13.21 +
13.22 +######## A graph showing the internal paging mechanism
13.23 +
13.24 +{{{#!graphviz
13.25 +#format svg
13.26 +#transform notugly
13.27 +digraph internal_paging {
13.28 + node [fontsize="12.0",fontname="sans-serif",shape=box];
13.29 + edge [fontsize="12.0",fontname="sans-serif"];
13.30 + rankdir=LR;
13.31 +
13.32 + TaskMemory [shape=record,label="Task Memory |<s> stack | ... |<d> data | ... |<c> code"];
13.33 +
13.34 + subgraph {
13.35 + rank=same;
13.36 +
13.37 + InternalPager;
13.38 + InternalPager_note [shape=note,style=filled,fillcolor=gold,label="Resides in\nsame task and\ndefines scope of\nfault resolution"];
13.39 +
13.40 + InternalPager -> InternalPager_note [dir=none,style=dotted];
13.41 + }
13.42 +
13.43 + subgraph {
13.44 + rank=same;
13.45 +
13.46 + Regions [shape=record,label="Regions |
13.47 + {<s> stack |<sd> stack-dataspace } |
13.48 + {<d> data | <dd> data-dataspace } |
13.49 + {<c> code |<cd> code-dataspace } |..."];
13.50 +
13.51 + ReceiveFlexpage [shape=note,label="Flexpage\n(receive window)"];
13.52 +
13.53 + Flexpage [shape=note];
13.54 + Flexpage_note [shape=note,style=filled,fillcolor=gold,label="Satisfies\nmemory\naccess"];
13.55 +
13.56 + Flexpage -> Flexpage_note [dir=none,style=dotted];
13.57 + }
13.58 +
13.59 + subgraph {
13.60 + rank=same;
13.61 +
13.62 + ResourceD [label="Resource\n(Pager)"];
13.63 + ResourceD_note [shape=note,style=filled,fillcolor=gold,label="Provides access\nto file content"];
13.64 +
13.65 + ResourceD -> ResourceD_note [dir=none,style=dotted];
13.66 + }
13.67 +
13.68 + ProgramFile [shape=record,label="Program File | ... |<d> data |<c> code | ..."];
13.69 +
13.70 + /* Page fault handling. */
13.71 +
13.72 + TaskMemory:d -> InternalPager [label="page fault"];
13.73 +
13.74 + InternalPager -> Regions:d [label="find region"];
13.75 +
13.76 + Regions:dd -> ResourceD [style=dashed];
13.77 +
13.78 + InternalPager -> ReceiveFlexpage [dir=none];
13.79 + ReceiveFlexpage -> ResourceD [label="map"];
13.80 +
13.81 + ResourceD -> ProgramFile:d [style=dashed];
13.82 +
13.83 + ResourceD -> Flexpage [dir=none];
13.84 + Flexpage -> InternalPager;
13.85 +}
13.86 +}}}
13.87 +
13.88 +########
13.89 +
13.90 +== External Page Fault Handlers ==
13.91 +
13.92 +Another approach that may be used to support an internal page fault handler
13.93 +deployed in a task is to employ an external page fault handler in the creating
13.94 +task. When a page fault occurs, the external handler ensures that the
13.95 +appropriate content has been brought into its own memory space. It then
13.96 +returns a flexpage from the handler routine to resolve the fault.
13.97 +
13.98 +######## A graph showing the external paging mechanism
13.99 +
13.100 +{{{#!graphviz
13.101 +#format svg
13.102 +#transform notugly
13.103 +digraph external_paging {
13.104 + node [fontsize="12.0",fontname="sans-serif",shape=box];
13.105 + edge [fontsize="12.0",fontname="sans-serif"];
13.106 + rankdir=LR;
13.107 +
13.108 + TaskMemory [shape=record,label="Task Memory |<s> stack | ... |<d> data | ... |<c> code"];
13.109 +
13.110 + subgraph {
13.111 + rank=same;
13.112 +
13.113 + ExternalPager_note [shape=note,style=filled,fillcolor=gold,label="Resides in\nseparate task"];
13.114 + ExternalPager;
13.115 +
13.116 + ExternalPager_note -> ExternalPager [dir=none,style=dotted];
13.117 +
13.118 + MappedFlexpage [shape=note,label="Flexpage\n(positioned)"];
13.119 + MappedFlexpage_note [shape=note,style=filled,fillcolor=gold,label="Satisfies\nmemory\naccess"];
13.120 +
13.121 + MappedFlexpage -> MappedFlexpage_note [dir=none,style=dotted];
13.122 + }
13.123 +
13.124 + subgraph {
13.125 + rank=same;
13.126 +
13.127 + Regions [shape=record,label="Regions |
13.128 + {<s> stack |<sd> stack-dataspace } |
13.129 + {<d> data | <dd> data-dataspace } |
13.130 + {<c> code |<cd> code-dataspace } |..."];
13.131 +
13.132 + L4Re [shape=ellipse,label="L4Re paging\nfunctionality"];
13.133 + L4Re_note [shape=note,style=filled,fillcolor=gold,label="Supports normal\naccess to file content"];
13.134 +
13.135 + L4Re -> L4Re_note [dir=none,style=dotted];
13.136 +
13.137 + Flexpage [shape=note];
13.138 + }
13.139 +
13.140 + subgraph {
13.141 + rank=same;
13.142 +
13.143 + ResourceD [label="Resource\n(Pager)"];
13.144 + ResourceD_note [shape=note,style=filled,fillcolor=gold,label="Provides access\nto file content"];
13.145 +
13.146 + ResourceD -> ResourceD_note [dir=none,style=dotted];
13.147 + }
13.148 +
13.149 + ProgramFile [shape=record,label="Program File | ... |<d> data |<c> code | ..."];
13.150 +
13.151 + /* Page fault handling. */
13.152 +
13.153 + TaskMemory:d -> ExternalPager [label="page fault"];
13.154 +
13.155 + ExternalPager -> Regions:d [label="find region"];
13.156 +
13.157 + Regions:dd -> ResourceD [style=dashed];
13.158 +
13.159 + ExternalPager -> L4Re;
13.160 + L4Re -> ResourceD [label="map"];
13.161 +
13.162 + ResourceD -> ProgramFile:d [style=dashed];
13.163 +
13.164 + ResourceD -> Flexpage [dir=none];
13.165 + Flexpage -> ExternalPager;
13.166 +
13.167 + ExternalPager -> MappedFlexpage [dir=none];
13.168 + MappedFlexpage -> TaskMemory:d;
13.169 +}
13.170 +}}}
13.171 +
13.172 +########
13.173 +
13.174 +== Configuring Programs ==
13.175 +
13.176 +To provide an internal page fault handler alongside an actual program to be
13.177 +run, the following arrangement is used:
13.178 +
13.179 +######## A graph showing the configuration arrangement
13.180 +
13.181 +{{{#!graphviz
13.182 +#format svg
13.183 +#transform notugly
13.184 +digraph program_configuration {
13.185 + node [fontsize="12.0",fontname="sans-serif",shape=box];
13.186 + edge [fontsize="12.0",fontname="sans-serif"];
13.187 + rankdir=LR;
13.188 +
13.189 + subgraph {
13.190 + rank=min;
13.191 +
13.192 + CreatingTask_note [shape=note,style=filled,fillcolor=gold,label="Responsible for\ncreating the\nnew task"];
13.193 + CreatingTask [label="Creating task"];
13.194 +
13.195 + CreatingTask_note -> CreatingTask [dir=none,style=dotted];
13.196 + }
13.197 +
13.198 + subgraph {
13.199 + rank=max;
13.200 +
13.201 + IPCGate_note [shape=note,style=filled,fillcolor=gold,label="Created for sharing\nbetween the tasks"];
13.202 + IPCGate [shape=octagon,label="IPC gate"];
13.203 +
13.204 + IPCGate_note -> IPCGate [dir=none,style=dotted];
13.205 + }
13.206 +
13.207 + InitCaps [shape=record,label="<head> Initial capabilities | {<s> \"server\" |<c> capability }"];
13.208 +
13.209 + subgraph {
13.210 + rank=same;
13.211 +
13.212 + InternalPager;
13.213 + InternalPager_note [shape=note,style=filled,fillcolor=gold,label="Starts and binds\nto IPC gate"];
13.214 +
13.215 + InternalPager -> InternalPager_note [dir=none,style=dotted];
13.216 +
13.217 + Program;
13.218 + Program_note [shape=note,style=filled,fillcolor=gold,label="Starts and references\npager via IPC gate"];
13.219 +
13.220 + Program -> Program_note [dir=none,style=dotted];
13.221 + }
13.222 +
13.223 + /* Create and transfer IPC gate for binding. */
13.224 +
13.225 + CreatingTask -> IPCGate [label="create"];
13.226 + CreatingTask -> InitCaps:head [label="define"];
13.227 + InitCaps:c -> IPCGate;
13.228 +
13.229 + /* Thread initiation. */
13.230 +
13.231 + CreatingTask -> InternalPager [label="start"];
13.232 + InternalPager -> InitCaps:s [label="bind"];
13.233 +
13.234 + CreatingTask -> Program [label="start"];
13.235 + Program -> IPCGate -> InternalPager [style=dashed];
13.236 +}
13.237 +}}}
13.238 +
13.239 +########
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/docs/wiki/ServerLibrary Wed Aug 10 00:25:44 2022 +0200
14.3 @@ -0,0 +1,245 @@
14.4 += Server Library =
14.5 +
14.6 +Within the filesystem server library, a number of different abstractions and
14.7 +mechanisms are employed to provide access to filesystem objects.
14.8 +
14.9 +<<TableOfContents(2,3)>>
14.10 +
14.11 +This document uses C-style interface syntax since the components operating
14.12 +within the described mechanisms will themselves be described using such
14.13 +syntax.
14.14 +
14.15 +== Accountable ==
14.16 +
14.17 +This interface provides the following operations:
14.18 +
14.19 +{{{
14.20 +void attach();
14.21 +unsigned int detach();
14.22 +}}}
14.23 +
14.24 +Its purpose is to provide reference counting for components, with the `attach`
14.25 +operation incrementing the number of users of a component, and with the
14.26 +`detach` operation decrementing the number of users and returning the
14.27 +resulting number of users. When components no longer have any attached users,
14.28 +they may perform operations to tidy up after themselves and permit their
14.29 +deallocation.
14.30 +
14.31 +== Accessors ==
14.32 +
14.33 +Accessors provide the means of accessing filesystem object data and metadata.
14.34 +Conceptually, files and directories are both exposed by accessors, although
14.35 +the interfaces and mechanisms may differ between these types of objects.
14.36 +
14.37 +=== Directory Accessors ===
14.38 +
14.39 +Currently, directory accessors provide support for traversing directory
14.40 +listings, obtaining the relevant filesystem metadata using the underlying
14.41 +filesystem access library.
14.42 +
14.43 +=== File Accessors ===
14.44 +
14.45 +File content is accessed through an interface with the following operations:
14.46 +
14.47 +{{{
14.48 +void close();
14.49 +void fill(Flexpage *flexpage);
14.50 +void flush(Flexpage *flexpage);
14.51 +offset_t get_size();
14.52 +void set_size(offset_t size);
14.53 +}}}
14.54 +
14.55 +The operations need to be supported with actual filesystem operations. For
14.56 +example, ext2-based filesystems employ a specific abstraction which invokes
14.57 +library functions provided by the `libext2fs` package.
14.58 +
14.59 +== Providers ==
14.60 +
14.61 +Providers encapsulate the essential functionality for accessing filesystem
14.62 +objects. Implementing the `Accountable` interface, they are shared by
14.63 +resources and discarded when no resources are using them.
14.64 +
14.65 +The following operations are supported by providers:
14.66 +
14.67 +{{{
14.68 +ProviderRegistry *registry();
14.69 +long make_resource(offset_t *size, object_flags_t *object_flags, Resource **resource);
14.70 +bool removal_pending();
14.71 +void remove();
14.72 +void remove_pending(bool remove);
14.73 +}}}
14.74 +
14.75 +Providers are associated with filesystem objects in a registry which can be
14.76 +obtained from each provider using the `registry` operation.
14.77 +
14.78 +Providers also support the creation of resources through which each user of a
14.79 +provider exercises its use of that provider. The `make_resource` operation
14.80 +performs the creation and returns size, flags and resource instance details.
14.81 +
14.82 +The removal of providers can be directed using the `remove_pending` and
14.83 +`remove` operations. Where `remove_pending` has been called with a true value
14.84 +as its parameter, the `removal_pending` operation will also return a true
14.85 +value, and upon the provider being discarded, the `remove` operation will be
14.86 +invoked. The `remove` operation performs the appropriate underlying operation
14.87 +to remove the object being provided.
14.88 +
14.89 +Typically, removal of providers is managed by the provider registry when
14.90 +resources are closed and detached from providers.
14.91 +
14.92 +######## A graph showing the removal mechanism
14.93 +
14.94 +{{{#!graphviz
14.95 +#format svg
14.96 +#transform notugly
14.97 +digraph provider_removal {
14.98 + node [fontsize="12.0",fontname="sans-serif",shape=box];
14.99 + edge [fontsize="12.0",fontname="sans-serif"];
14.100 + rankdir=LR;
14.101 +
14.102 + ResourceServer -> Resource [label="close"];
14.103 + Resource -> ProviderRegistry [label="detach"];
14.104 + ProviderRegistry -> Provider [label="remove"];
14.105 +}
14.106 +}}}
14.107 +
14.108 +########
14.109 +
14.110 +== Resources ==
14.111 +
14.112 +Resources are objects accessed by clients that support a basic level of
14.113 +accounting and management.
14.114 +
14.115 +The base interface of a resource is as follows:
14.116 +
14.117 +{{{
14.118 +void activate();
14.119 +void close();
14.120 +}}}
14.121 +
14.122 +Activation of a resource is an optional operation that performs any
14.123 +initialisation before a resource is made available to its user.
14.124 +
14.125 +In practice, other operations are required to make resources useful.
14.126 +
14.127 +In some cases, resources provide the mechanism by which each user of a
14.128 +filesystem object may access that object independently. They would then
14.129 +effectively provide a session in which accesses can occur.
14.130 +
14.131 +=== Directory Resources ===
14.132 +
14.133 +Directory resources primarily expose the contents of directories in the
14.134 +filesystem to a user. They employ directory accessors which concern themselves
14.135 +with the actual filesystem content.
14.136 +
14.137 +[[Components#Directories|Directory components]] are provided using directory
14.138 +resources.
14.139 +
14.140 +<<Anchor(Pager)>>
14.141 +=== Pagers or File Resources ===
14.142 +
14.143 +Pagers are resources that support dataspace access operations, thus allowing
14.144 +the resources to expose filesystem content in mapped memory regions to a
14.145 +particular user of the object providing the content.
14.146 +
14.147 +[[Components#Files|File components]] and [[Components#Pipes|pipe components]]
14.148 +are provided using pagers.
14.149 +
14.150 +=== Filesystem Resources ===
14.151 +
14.152 +Filesystem resources provide the entry point for access to a filesystem by
14.153 +other components or programs. Since filesystems often enforce identity-based
14.154 +access controls, a filesystem resource will typically support the
14.155 +`open_for_user` operation in various forms, with the result of this operation
14.156 +being the instantiation of an `OpenerResource` configured for the indicated
14.157 +user identity.
14.158 +
14.159 +== Registries ==
14.160 +
14.161 +The basic mechanism for obtaining a resource involves a registry, as
14.162 +illustrated by the following diagram.
14.163 +
14.164 +######## A graph showing the use of a registry in obtaining resources
14.165 +
14.166 +{{{#!graphviz
14.167 +#format svg
14.168 +#transform notugly
14.169 +digraph registry {
14.170 + node [fontsize="12.0",fontname="sans-serif",shape=box];
14.171 + edge [fontsize="12.0",fontname="sans-serif"];
14.172 + rankdir=LR;
14.173 +
14.174 + subgraph {
14.175 + node [label="OpenerContextResource"];
14.176 + rank=same;
14.177 +
14.178 + OpenerContextResource1 -> OpenerContextResource2 [dir=none,style=dotted];
14.179 + }
14.180 +
14.181 + subgraph {
14.182 + node [label="OpenerResource"];
14.183 + rank=same;
14.184 +
14.185 + OpenerResource1 -> OpenerResource2 [dir=none,style=dotted];
14.186 + }
14.187 +
14.188 + subgraph {
14.189 + rank=same;
14.190 +
14.191 + ResourceRegistry -> Resource;
14.192 + }
14.193 +
14.194 + subgraph {
14.195 + rank=same;
14.196 +
14.197 + ProviderRegistry -> Provider;
14.198 + }
14.199 +
14.200 + OpenerContextResource1 -> OpenerResource1 [label="open"];
14.201 + OpenerResource1 -> ResourceRegistry [label="get_resource"];
14.202 + ResourceRegistry -> ProviderRegistry [label="get/set"];
14.203 +
14.204 + Provider -> Resource -> OpenerResource2 -> OpenerContextResource2;
14.205 +}
14.206 +}}}
14.207 +
14.208 +########
14.209 +
14.210 +The `ResourceRegistry` coordinates access to filesystem resources and, through
14.211 +synchronisation, prevents conflicting operations from occurring concurrently.
14.212 +For example, a removal operation on a file may not be allowed to occur while
14.213 +an opening operation is in progress.
14.214 +
14.215 +To achieve this, a common lock is employed to serialise access, with any
14.216 +underlying filesystem operations being initiated from the registry while the
14.217 +lock is held. An object providing the `FileOpening` interface for a filesystem
14.218 +provides such operations, and the following interaction pattern is thereby
14.219 +employed:
14.220 +
14.221 +######## A graph showing the registry coordinating filesystem operations
14.222 +
14.223 +{{{#!graphviz
14.224 +#format svg
14.225 +#transform notugly
14.226 +digraph registry_operations {
14.227 + node [fontsize="12.0",fontname="sans-serif",shape=box];
14.228 + edge [fontsize="12.0",fontname="sans-serif"];
14.229 + rankdir=LR;
14.230 +
14.231 + OpenerContextResource -> OpenerResource -> ResourceRegistry -> FileOpening;
14.232 +}
14.233 +}}}
14.234 +
14.235 +########
14.236 +
14.237 +Since the `ResourceRegistry` functionality is generic, it could be specialised
14.238 +for each filesystem or be configured with an appropriate reference to a
14.239 +`FileOpening` object. The `OpenerResource` would then be generic, invoking the
14.240 +registry which would, in turn, invoke the opening object.
14.241 +
14.242 +However, the chosen approach is to permit `OpenerResource` objects to
14.243 +implement the `FileOpening` interface for each filesystem, meaning that the
14.244 +`ResourceRegistry` will end up being called by the opener and then invoking
14.245 +the opener in return. This is slightly more convenient than the alternative
14.246 +since the opener can be configured with a given user identity, and such
14.247 +identity details will ultimately be employed when accessing the underlying
14.248 +filesystem itself.
15.1 --- a/libexec/Makefile Sun Jun 12 17:10:30 2022 +0200
15.2 +++ b/libexec/Makefile Wed Aug 10 00:25:44 2022 +0200
15.3 @@ -1,4 +1,10 @@
15.4 PKGDIR ?= .
15.5 L4DIR ?= $(PKGDIR)/../../..
15.6
15.7 +TARGET = include lib rm
15.8 +
15.9 include $(L4DIR)/mk/subdir.mk
15.10 +
15.11 +# Internal dependencies.
15.12 +
15.13 +rm: lib
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/libexec/include/exec/common.h Wed Aug 10 00:25:44 2022 +0200
16.3 @@ -0,0 +1,58 @@
16.4 +/*
16.5 + * Common structures and functions.
16.6 + *
16.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
16.8 + *
16.9 + * This program is free software; you can redistribute it and/or
16.10 + * modify it under the terms of the GNU General Public License as
16.11 + * published by the Free Software Foundation; either version 2 of
16.12 + * the License, or (at your option) any later version.
16.13 + *
16.14 + * This program is distributed in the hope that it will be useful,
16.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
16.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16.17 + * GNU General Public License for more details.
16.18 + *
16.19 + * You should have received a copy of the GNU General Public License
16.20 + * along with this program; if not, write to the Free Software
16.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
16.22 + * Boston, MA 02110-1301, USA
16.23 + */
16.24 +
16.25 +#pragma once
16.26 +
16.27 +#include <l4/re/l4aux.h>
16.28 +
16.29 +#include <systypes/base.h>
16.30 +
16.31 +
16.32 +
16.33 +EXTERN_C_BEGIN
16.34 +
16.35 +/* Auxiliary vector key-value pair. */
16.36 +
16.37 +struct auxv_entry
16.38 +{
16.39 + l4_umword_t key, value;
16.40 +};
16.41 +
16.42 +/* Region description. */
16.43 +
16.44 +struct exec_region
16.45 +{
16.46 + l4_addr_t start;
16.47 + offset_t size;
16.48 + l4_umword_t flags;
16.49 + l4_cap_idx_t ds;
16.50 +};
16.51 +
16.52 +
16.53 +
16.54 +/* Utility functions. */
16.55 +
16.56 +l4re_aux_t *exec_get_l4re_aux(int argc, char *argv[]);
16.57 +
16.58 +EXTERN_C_END
16.59 +
16.60 +/* vim: tabstop=2 expandtab shiftwidth=2
16.61 +*/
17.1 --- a/libexec/include/exec/elf.h Sun Jun 12 17:10:30 2022 +0200
17.2 +++ b/libexec/include/exec/elf.h Wed Aug 10 00:25:44 2022 +0200
17.3 @@ -19,27 +19,16 @@
17.4 * Boston, MA 02110-1301, USA
17.5 */
17.6
17.7 +#pragma once
17.8 +
17.9 #include <exec/segment.h>
17.10
17.11
17.12
17.13 /* Generic program segment interface. */
17.14
17.15 -class ProgramSegment
17.16 -{
17.17 -public:
17.18 - virtual bool loadable() = 0;
17.19 - virtual offset_t file_contents() = 0;
17.20 - virtual offset_t file_offset() = 0;
17.21 - virtual l4_addr_t region_address() = 0;
17.22 - virtual offset_t region_size() = 0;
17.23 - virtual l4re_rm_flags_t region_flags() = 0;
17.24 -
17.25 - Segment *segment();
17.26 -};
17.27 -
17.28 template <typename PROGRAM_HEADER>
17.29 -class ProgramSegmentVariant : public ProgramSegment
17.30 +class ProgramSegmentVariant : public Segment
17.31 {
17.32 protected:
17.33 PROGRAM_HEADER *_header;
17.34 @@ -55,18 +44,23 @@
17.35 l4re_rm_flags_t region_flags();
17.36 };
17.37
17.38 -
17.39 +
17.40
17.41 /* Generic interface for an ELF payload. */
17.42
17.43 class Payload
17.44 {
17.45 +protected:
17.46 + Segment **_segments = NULL;
17.47 +
17.48 public:
17.49 + virtual ~Payload();
17.50 +
17.51 virtual l4_addr_t entry_point() = 0;
17.52 virtual offset_t header_extent() = 0;
17.53 virtual offset_t program_header_extent() = 0;
17.54 - virtual unsigned int segments() = 0;
17.55 - virtual ProgramSegment *segment(unsigned int i) = 0;
17.56 + virtual unsigned int segments();
17.57 + virtual Segment *segment(unsigned int i) = 0;
17.58 };
17.59
17.60 template <typename HEADER, typename PROGRAM_HEADER>
17.61 @@ -82,14 +76,14 @@
17.62 offset_t header_extent();
17.63 offset_t program_header_extent();
17.64 unsigned int segments();
17.65 - ProgramSegment *segment(unsigned int i);
17.66 + Segment *segment(unsigned int i);
17.67 };
17.68
17.69
17.70
17.71 /* Return the appropriate payload object. */
17.72
17.73 -Payload *get_payload(char *buf);
17.74 +Payload *exec_open_payload(char *buf);
17.75
17.76 /* vim: tabstop=2 expandtab shiftwidth=2
17.77 */
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/libexec/include/exec/external_pager.h Wed Aug 10 00:25:44 2022 +0200
18.3 @@ -0,0 +1,63 @@
18.4 +/*
18.5 + * A system pager implementation residing in a separate task.
18.6 + *
18.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
18.8 + *
18.9 + * This program is free software; you can redistribute it and/or
18.10 + * modify it under the terms of the GNU General Public License as
18.11 + * published by the Free Software Foundation; either version 2 of
18.12 + * the License, or (at your option) any later version.
18.13 + *
18.14 + * This program is distributed in the hope that it will be useful,
18.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
18.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18.17 + * GNU General Public License for more details.
18.18 + *
18.19 + * You should have received a copy of the GNU General Public License
18.20 + * along with this program; if not, write to the Free Software
18.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18.22 + * Boston, MA 02110-1301, USA
18.23 + */
18.24 +
18.25 +#pragma once
18.26 +
18.27 +#include <map>
18.28 +
18.29 +#include <exec/mapped_region.h>
18.30 +#include <exec/pager.h>
18.31 +
18.32 +
18.33 +
18.34 +/* Collection types. */
18.35 +
18.36 +typedef std::map<l4_addr_t, MappedRegion> MappedRegions;
18.37 +
18.38 +
18.39 +
18.40 +/* A simple system pager also acting as a region mapper. */
18.41 +
18.42 +class ExternalPager : public ExecPager
18.43 +{
18.44 +protected:
18.45 + MappedRegions _regions;
18.46 +
18.47 +public:
18.48 + virtual void add(MappedRegion ®ion);
18.49 +
18.50 + /* Notification methods, implementing PagerObject. */
18.51 +
18.52 + virtual long exception(l4_exc_regs_t regs,
18.53 + l4_snd_fpage_t *region);
18.54 +
18.55 + virtual long page_fault(l4_umword_t pfa, l4_umword_t pc,
18.56 + l4_snd_fpage_t *region);
18.57 +
18.58 + /* Region manager/mapper methods. */
18.59 +
18.60 + virtual long attach(address_t *start, offset_t size, map_flags_t flags,
18.61 + l4_cap_idx_t ds, address_t offset, unsigned char align);
18.62 +
18.63 +};
18.64 +
18.65 +/* vim: tabstop=2 expandtab shiftwidth=2
18.66 +*/
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/libexec/include/exec/internal_pager.h Wed Aug 10 00:25:44 2022 +0200
19.3 @@ -0,0 +1,64 @@
19.4 +/*
19.5 + * A system pager implementation residing in the same task as a program.
19.6 + *
19.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
19.8 + *
19.9 + * This program is free software; you can redistribute it and/or
19.10 + * modify it under the terms of the GNU General Public License as
19.11 + * published by the Free Software Foundation; either version 2 of
19.12 + * the License, or (at your option) any later version.
19.13 + *
19.14 + * This program is distributed in the hope that it will be useful,
19.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
19.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19.17 + * GNU General Public License for more details.
19.18 + *
19.19 + * You should have received a copy of the GNU General Public License
19.20 + * along with this program; if not, write to the Free Software
19.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19.22 + * Boston, MA 02110-1301, USA
19.23 + */
19.24 +
19.25 +#pragma once
19.26 +
19.27 +#include <map>
19.28 +
19.29 +#include <exec/common.h>
19.30 +#include <exec/pager.h>
19.31 +
19.32 +
19.33 +
19.34 +/* Collection types. */
19.35 +
19.36 +typedef std::map<l4_addr_t, struct exec_region> ExecRegions;
19.37 +typedef struct exec_region ExecRegion;
19.38 +
19.39 +
19.40 +
19.41 +/* A simple system pager also acting as a region mapper. */
19.42 +
19.43 +class InternalPager : public ExecPager
19.44 +{
19.45 +protected:
19.46 + ExecRegions _regions;
19.47 +
19.48 +public:
19.49 + virtual void add(ExecRegion ®ion);
19.50 +
19.51 + /* Notification methods, implementing PagerObject. */
19.52 +
19.53 + virtual long exception(l4_exc_regs_t regs,
19.54 + l4_snd_fpage_t *region);
19.55 +
19.56 + virtual long page_fault(l4_umword_t pfa, l4_umword_t pc,
19.57 + l4_snd_fpage_t *region);
19.58 +
19.59 + /* Region manager/mapper methods. */
19.60 +
19.61 + virtual long attach(address_t *start, offset_t size, map_flags_t flags,
19.62 + l4_cap_idx_t ds, address_t offset, unsigned char align);
19.63 +
19.64 +};
19.65 +
19.66 +/* vim: tabstop=2 expandtab shiftwidth=2
19.67 +*/
20.1 --- a/libexec/include/exec/mapped_region.h Sun Jun 12 17:10:30 2022 +0200
20.2 +++ b/libexec/include/exec/mapped_region.h Wed Aug 10 00:25:44 2022 +0200
20.3 @@ -36,15 +36,17 @@
20.4 offset_t size;
20.5 l4_umword_t flags;
20.6 l4_addr_t map_start;
20.7 + l4_cap_idx_t ds;
20.8
20.9 explicit MappedRegion()
20.10 - : start(0), size(0), flags(0), map_start(0)
20.11 + : start(0), size(0), flags(0), map_start(0), ds(L4_INVALID_CAP)
20.12 {
20.13 }
20.14
20.15 explicit MappedRegion(l4_addr_t start, l4_addr_t size,
20.16 - l4_umword_t flags, l4_addr_t map_start)
20.17 - : start(start), size(size), flags(flags), map_start(map_start)
20.18 + l4_umword_t flags, l4_addr_t map_start,
20.19 + l4_cap_idx_t ds = L4_INVALID_CAP)
20.20 + : start(start), size(size), flags(flags), map_start(map_start), ds(ds)
20.21 {
20.22 }
20.23 };
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/libexec/include/exec/memory.h Wed Aug 10 00:25:44 2022 +0200
21.3 @@ -0,0 +1,34 @@
21.4 +/*
21.5 + * Program memory initialisation support.
21.6 + *
21.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
21.8 + *
21.9 + * This program is free software; you can redistribute it and/or
21.10 + * modify it under the terms of the GNU General Public License as
21.11 + * published by the Free Software Foundation; either version 2 of
21.12 + * the License, or (at your option) any later version.
21.13 + *
21.14 + * This program is distributed in the hope that it will be useful,
21.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
21.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21.17 + * GNU General Public License for more details.
21.18 + *
21.19 + * You should have received a copy of the GNU General Public License
21.20 + * along with this program; if not, write to the Free Software
21.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
21.22 + * Boston, MA 02110-1301, USA
21.23 + */
21.24 +
21.25 +#pragma once
21.26 +
21.27 +#include <exec/elf.h>
21.28 +#include <exec/segment.h>
21.29 +
21.30 +
21.31 +
21.32 +/* Initialisation functions. */
21.33 +
21.34 +long exec_get_payload(const char *filename, Payload **payload, bool attach);
21.35 +
21.36 +/* vim: tabstop=2 expandtab shiftwidth=2
21.37 +*/
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/libexec/include/exec/pager.h Wed Aug 10 00:25:44 2022 +0200
22.3 @@ -0,0 +1,51 @@
22.4 +/*
22.5 + * A system pager interface.
22.6 + *
22.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
22.8 + *
22.9 + * This program is free software; you can redistribute it and/or
22.10 + * modify it under the terms of the GNU General Public License as
22.11 + * published by the Free Software Foundation; either version 2 of
22.12 + * the License, or (at your option) any later version.
22.13 + *
22.14 + * This program is distributed in the hope that it will be useful,
22.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
22.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22.17 + * GNU General Public License for more details.
22.18 + *
22.19 + * You should have received a copy of the GNU General Public License
22.20 + * along with this program; if not, write to the Free Software
22.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
22.22 + * Boston, MA 02110-1301, USA
22.23 + */
22.24 +
22.25 +#pragma once
22.26 +
22.27 +#include "pager_object_interface.h"
22.28 +
22.29 +
22.30 +
22.31 +/* A simple system pager also acting as a region mapper. */
22.32 +
22.33 +class ExecPager : public PagerObject
22.34 +{
22.35 +public:
22.36 + virtual ~ExecPager();
22.37 +
22.38 + /* Notification methods. */
22.39 +
22.40 + virtual long exception(l4_exc_regs_t regs,
22.41 + l4_snd_fpage_t *region) = 0;
22.42 +
22.43 + virtual long page_fault(l4_umword_t pfa, l4_umword_t pc,
22.44 + l4_snd_fpage_t *region);
22.45 +
22.46 + /* Region manager/mapper methods. */
22.47 +
22.48 + virtual long attach(address_t *start, offset_t size, map_flags_t flags,
22.49 + l4_cap_idx_t ds, address_t offset, unsigned char align);
22.50 +
22.51 +};
22.52 +
22.53 +/* vim: tabstop=2 expandtab shiftwidth=2
22.54 +*/
23.1 --- a/libexec/include/exec/process.h Sun Jun 12 17:10:30 2022 +0200
23.2 +++ b/libexec/include/exec/process.h Wed Aug 10 00:25:44 2022 +0200
23.3 @@ -50,17 +50,18 @@
23.4
23.5 enum exec_task_caps
23.6 {
23.7 - L4_EXEC_PAGER_CAP = 0x10 << L4_CAP_SHIFT,
23.8 - L4_EXEC_RM_CAP = 0x11 << L4_CAP_SHIFT,
23.9 - L4_EXEC_MA_CAP = 0x12 << L4_CAP_SHIFT,
23.10 - L4_EXEC_KIP_CAP = 0x14 << L4_CAP_SHIFT,
23.11 + L4_EXEC_PAGER_CAP = 0x10UL << L4_CAP_SHIFT,
23.12 + L4_EXEC_RM_CAP = 0x11UL << L4_CAP_SHIFT,
23.13 + L4_EXEC_MA_CAP = 0x12UL << L4_CAP_SHIFT,
23.14 + L4_EXEC_KIP_CAP = 0x14UL << L4_CAP_SHIFT,
23.15 };
23.16
23.17 -/* The default first free capability index must follow those above. */
23.18 +/* The default first free capability index must follow those above. Any
23.19 + additional initial capabilities must elevate the index below. */
23.20
23.21 enum exec_task_cap_indexes
23.22 {
23.23 - L4_EXEC_FIRST_FREE_CAP_INDEX = 0x15,
23.24 + L4_EXEC_FIRST_FREE_CAP_INDEX = 0x15UL,
23.25 };
23.26
23.27
23.28 @@ -76,7 +77,7 @@
23.29
23.30 l4_addr_t _utcb_start;
23.31
23.32 - /* Common environment details. */
23.33 + /* Common and thread environment details. */
23.34
23.35 l4re_aux_t _aux;
23.36 l4re_env_t _env;
23.37 @@ -88,9 +89,16 @@
23.38 long create_thread(l4_cap_idx_t *thread);
23.39
23.40 public:
23.41 - explicit Process();
23.42 + explicit Process(int reserved_threads = 1);
23.43 +
23.44 + l4_cap_idx_t allocate_cap();
23.45
23.46 - long configure(l4_cap_idx_t server);
23.47 + long configure_task();
23.48 +
23.49 + long configure_thread(l4_cap_idx_t server, l4_cap_idx_t mapped_cap = L4_INVALID_CAP);
23.50 +
23.51 + long map_capabilities(struct ipc_mapped_cap mapped_caps[],
23.52 + bool to_count = true);
23.53
23.54 long thread_start(l4_addr_t program_start, Stack &st);
23.55 };
24.1 --- a/libexec/include/exec/segment.h Sun Jun 12 17:10:30 2022 +0200
24.2 +++ b/libexec/include/exec/segment.h Wed Aug 10 00:25:44 2022 +0200
24.3 @@ -26,45 +26,44 @@
24.4
24.5 #include <fsclient/client.h>
24.6
24.7 +#include <exec/common.h>
24.8 #include <exec/mapped_region.h>
24.9
24.10
24.11
24.12 -/* Program segment abstraction. */
24.13 +/* Program segment abstractions. */
24.14
24.15 class Segment
24.16 {
24.17 protected:
24.18 MappedRegion _region;
24.19 + struct exec_region _exec_region;
24.20
24.21 /* Allocated memory. */
24.22
24.23 char *_buf;
24.24 l4re_ds_t _ds;
24.25
24.26 - /* Segment base and corresponding region base. */
24.27 + /* Segment region base. */
24.28
24.29 - l4_addr_t _base, _region_base;
24.30 + l4_addr_t _region_base;
24.31
24.32 - /* Segment size and corresponding region size. */
24.33 + /* Segment region size. */
24.34
24.35 - offset_t _size, _region_size;
24.36 + offset_t _region_allocated_size;
24.37
24.38 /* Offset of segment content within the region. */
24.39
24.40 - offset_t _region_offset;
24.41 -
24.42 - /* Access flags. */
24.43 + offset_t _region_content_offset;
24.44
24.45 - l4re_rm_flags_t _flags;
24.46 + /* Common initialisation. */
24.47
24.48 - /* File access details. */
24.49 -
24.50 - offset_t _file_offset, _file_contents;
24.51 + void init();
24.52
24.53 public:
24.54 - explicit Segment(l4_addr_t base, offset_t size, l4re_rm_flags_t flags,
24.55 - offset_t file_offset = 0, offset_t file_contents = 0);
24.56 + virtual ~Segment();
24.57 +
24.58 + l4_cap_idx_t cap();
24.59
24.60 char *address();
24.61
24.62 @@ -72,9 +71,9 @@
24.63
24.64 /* Segment population methods. */
24.65
24.66 - long allocate();
24.67 + long allocate(bool attach);
24.68
24.69 - long fill(file_t *file);
24.70 + long fill(file_t *file, bool attach);
24.71
24.72 /* Mapped region methods. */
24.73
24.74 @@ -86,8 +85,48 @@
24.75
24.76 /* Generic property access. */
24.77
24.78 + struct exec_region &exec_region();
24.79 +
24.80 + virtual bool loadable() = 0;
24.81 + virtual offset_t file_contents() = 0;
24.82 + virtual offset_t file_offset() = 0;
24.83 + virtual l4_addr_t region_address() = 0;
24.84 + virtual offset_t region_size() = 0;
24.85 + virtual l4re_rm_flags_t region_flags() = 0;
24.86 +};
24.87 +
24.88 +
24.89 +
24.90 +class ExplicitSegment : public Segment
24.91 +{
24.92 +protected:
24.93 + /* Segment base. */
24.94 +
24.95 + l4_addr_t _base;
24.96 +
24.97 + /* Segment size. */
24.98 +
24.99 + offset_t _size;
24.100 +
24.101 + /* Access flags. */
24.102 +
24.103 + l4re_rm_flags_t _flags;
24.104 +
24.105 + /* File access details. */
24.106 +
24.107 + offset_t _file_offset, _file_contents;
24.108 +
24.109 +public:
24.110 + explicit ExplicitSegment(l4_addr_t base, offset_t size, l4re_rm_flags_t flags,
24.111 + offset_t file_offset = 0, offset_t file_contents = 0);
24.112 +
24.113 + /* Generic property access. */
24.114 +
24.115 + bool loadable();
24.116 offset_t file_contents();
24.117 -
24.118 + offset_t file_offset();
24.119 + l4_addr_t region_address();
24.120 + offset_t region_size();
24.121 l4re_rm_flags_t region_flags();
24.122 };
24.123
25.1 --- a/libexec/include/exec/stack.h Sun Jun 12 17:10:30 2022 +0200
25.2 +++ b/libexec/include/exec/stack.h Wed Aug 10 00:25:44 2022 +0200
25.3 @@ -22,8 +22,8 @@
25.4 #pragma once
25.5
25.6 #include <l4/re/env.h>
25.7 -#include <l4/re/l4aux.h>
25.8
25.9 +#include <exec/common.h>
25.10 #include <exec/segment.h>
25.11
25.12
25.13 @@ -34,13 +34,6 @@
25.14 {
25.15 protected:
25.16
25.17 - /* Auxiliary vector key-value pair. */
25.18 -
25.19 - struct auxv_entry
25.20 - {
25.21 - l4_umword_t key, value;
25.22 - };
25.23 -
25.24 /* Program segment holding the stack contents. */
25.25
25.26 Segment &_segment;
25.27 @@ -51,25 +44,30 @@
25.28
25.29 /* Stack section properties. */
25.30
25.31 - l4_addr_t _caps;
25.32 + l4_addr_t _regions = 0;
25.33 + l4_addr_t _caps = 0;
25.34 + int _num_caps = 0;
25.35 char *_arg_top, *_env_top;
25.36 char **_argv;
25.37 char *_auxv_end;
25.38 - int _env_entries;
25.39 + int _env_entries = 0;
25.40
25.41 /* L4Re auxiliary and environment regions. */
25.42
25.43 l4re_aux_t *_aux;
25.44 l4re_env_t *_env;
25.45
25.46 + /* Any indicated initial capabilities and regions. */
25.47 +
25.48 + l4re_env_cap_entry_t *_cap_entries = NULL;
25.49 + struct exec_region *_region_entries = NULL;
25.50 +
25.51 /* Stack pointer start address. */
25.52
25.53 l4_addr_t _start;
25.54
25.55 /* Internal stack population methods. */
25.56
25.57 - void push_cap_entries(l4re_env_cap_entry_t *entries);
25.58 -
25.59 void push_string(char *s);
25.60
25.61 void push_env(char *envp[]);
25.62 @@ -82,6 +80,10 @@
25.63
25.64 void push_auxv();
25.65
25.66 + void push_init_caps();
25.67 +
25.68 + void push_regions();
25.69 +
25.70 offset_t write_address(char *arg, char **addr, char *s);
25.71
25.72 void push_envp(char *envp[]);
25.73 @@ -93,6 +95,10 @@
25.74 public:
25.75 explicit Stack(Segment &segment);
25.76
25.77 + void set_init_caps(l4re_env_cap_entry_t *entries);
25.78 +
25.79 + void set_regions(struct exec_region *regions);
25.80 +
25.81 void set_l4re_aux(l4re_aux_t *aux);
25.82
25.83 void set_l4re_env(l4re_env_t *env);
26.1 --- a/libexec/lib/src/Makefile Sun Jun 12 17:10:30 2022 +0200
26.2 +++ b/libexec/lib/src/Makefile Wed Aug 10 00:25:44 2022 +0200
26.3 @@ -3,10 +3,56 @@
26.4
26.5 TARGET = libexec.a libexec.so
26.6 PC_FILENAME = libexec
26.7 -SRC_CC = elf.cc process.cc segment.cc stack.cc
26.8 -REQUIRES_LIBS = l4re_c-util libmem libipc libstdc++ libsystypes libfsclient
26.9 +
26.10 +# Locations for interface input and generated output.
26.11 +
26.12 +IDL_DIR = $(PKGDIR)/../libsystypes/idl
26.13 +IDL_MK_DIR = $(L4DIR)/idl4re/mk
26.14 +IDL_BUILD_DIR = .
26.15 +IDL_EXPORT_DIR = .
26.16 +
26.17 +include $(IDL_MK_DIR)/idl.mk
26.18 +
26.19 +# Compound interfaces.
26.20 +
26.21 +pager_object_NAME = PagerObject
26.22 +pager_object_INTERFACES = region_mapper system_pager
26.23 +
26.24 +COMP_INTERFACES_CC = pager_object
26.25 +
26.26 +# Individual interfaces.
26.27 +
26.28 +CLIENT_INTERFACES_CC = dataspace mapped_file
26.29 +
26.30 +SERVER_INTERFACES_CC = $(call common_interfaces,$(COMP_INTERFACES_CC))
26.31
26.32 -PRIVATE_INCDIR += $(PKGDIR)/include/exec
26.33 +# Generated and plain source files.
26.34 +
26.35 +CLIENT_INTERFACES_SRC_CC = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC))
26.36 +
26.37 +SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC) $(COMP_INTERFACES_CC))
26.38 +
26.39 +# Normal source files.
26.40 +
26.41 +PLAIN_SRC_CC = \
26.42 + common.cc elf.cc external_pager.cc \
26.43 + internal_pager.cc memory.cc pager.cc \
26.44 + process.cc segment.cc stack.cc
26.45 +
26.46 +# Normal definitions.
26.47 +
26.48 +SRC_CC = \
26.49 + $(CLIENT_INTERFACES_SRC_CC) \
26.50 + $(SERVER_INTERFACES_SRC_CC) \
26.51 + $(PLAIN_SRC_CC)
26.52 +
26.53 +REQUIRES_LIBS = l4re_c-util libmem libipc libstdc++ libsystypes libfsclient
26.54 +
26.55 +PRIVATE_INCDIR = $(PKGDIR)/include/exec $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR)
26.56 +
26.57 CONTRIB_INCDIR = libexec
26.58
26.59 include $(L4DIR)/mk/lib.mk
26.60 +include $(IDL_MK_DIR)/interface_rules.mk
26.61 +
26.62 +$(PLAIN_SRC_CC): $(CLIENT_INTERFACES_SRC_CC) $(SERVER_INTERFACES_SRC_CC)
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/libexec/lib/src/common.cc Wed Aug 10 00:25:44 2022 +0200
27.3 @@ -0,0 +1,59 @@
27.4 +/*
27.5 + * Common functionality.
27.6 + *
27.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
27.8 + *
27.9 + * This program is free software; you can redistribute it and/or
27.10 + * modify it under the terms of the GNU General Public License as
27.11 + * published by the Free Software Foundation; either version 2 of
27.12 + * the License, or (at your option) any later version.
27.13 + *
27.14 + * This program is distributed in the hope that it will be useful,
27.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
27.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27.17 + * GNU General Public License for more details.
27.18 + *
27.19 + * You should have received a copy of the GNU General Public License
27.20 + * along with this program; if not, write to the Free Software
27.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
27.22 + * Boston, MA 02110-1301, USA
27.23 + */
27.24 +
27.25 +#include <l4/util/elf.h>
27.26 +
27.27 +#include "common.h"
27.28 +
27.29 +
27.30 +
27.31 +/* Find the L4Re auxiliary structure from program argument details. */
27.32 +
27.33 +l4re_aux_t *exec_get_l4re_aux(int argc, char *argv[])
27.34 +{
27.35 + /* Start after the final terminator (at argc) of the argument vector. */
27.36 +
27.37 + l4_umword_t *arg = ((l4_umword_t *) &argv[argc]) + 1;
27.38 +
27.39 + /* The environment vector is traversed. */
27.40 +
27.41 + while (*arg)
27.42 + arg++;
27.43 +
27.44 + /* Skip the terminating null entry. */
27.45 +
27.46 + arg++;
27.47 +
27.48 + /* Traverse the auxiliary vector. */
27.49 +
27.50 + struct auxv_entry *entry = (struct auxv_entry *) arg;
27.51 +
27.52 + for (; entry->key; entry++)
27.53 + {
27.54 + if (entry->key == AT_L4_AUX)
27.55 + return (l4re_aux_t *) entry->value;
27.56 + }
27.57 +
27.58 + return NULL;
27.59 +}
27.60 +
27.61 +/* vim: tabstop=2 expandtab shiftwidth=2
27.62 +*/
28.1 --- a/libexec/lib/src/elf.cc Sun Jun 12 17:10:30 2022 +0200
28.2 +++ b/libexec/lib/src/elf.cc Wed Aug 10 00:25:44 2022 +0200
28.3 @@ -25,26 +25,13 @@
28.4
28.5
28.6
28.7 -/* Generic segment creation from program segments. */
28.8 -
28.9 -Segment *ProgramSegment::segment()
28.10 -{
28.11 - return new Segment(
28.12 - region_address(),
28.13 - region_size(),
28.14 - region_flags(),
28.15 - file_offset(),
28.16 - file_contents());
28.17 -}
28.18 -
28.19 -
28.20 -
28.21 /* Program segment construction for 32- or 64-bit variants. */
28.22
28.23 template <typename PROGRAM_HEADER>
28.24 ProgramSegmentVariant<PROGRAM_HEADER>::ProgramSegmentVariant(PROGRAM_HEADER *header)
28.25 : _header(header)
28.26 {
28.27 + init();
28.28 }
28.29
28.30 template <typename PROGRAM_HEADER>
28.31 @@ -94,6 +81,24 @@
28.32
28.33
28.34
28.35 +/* Generic payload destruction. */
28.36 +
28.37 +Payload::~Payload()
28.38 +{
28.39 + if (_segments != NULL)
28.40 + {
28.41 + for (unsigned int i = 0; i < segments(); i++)
28.42 + delete _segments[i];
28.43 + }
28.44 +}
28.45 +
28.46 +unsigned int Payload::segments()
28.47 +{
28.48 + return 0;
28.49 +}
28.50 +
28.51 +
28.52 +
28.53 /* ELF payload construction for 32- or 64-bit variants. */
28.54
28.55 template <typename HEADER, typename PROGRAM_HEADER>
28.56 @@ -127,21 +132,37 @@
28.57 }
28.58
28.59 template <typename HEADER, typename PROGRAM_HEADER>
28.60 -ProgramSegment *PayloadVariant<HEADER, PROGRAM_HEADER>::segment(unsigned int i)
28.61 +Segment *PayloadVariant<HEADER, PROGRAM_HEADER>::segment(unsigned int i)
28.62 {
28.63 if (i >= segments())
28.64 return NULL;
28.65
28.66 - return new ProgramSegmentVariant<PROGRAM_HEADER>(
28.67 - (PROGRAM_HEADER *) ((char *) _header + _header->e_phoff +
28.68 - _header->e_phentsize * i));
28.69 + if (_segments == NULL)
28.70 + {
28.71 + _segments = new Segment *[segments()];
28.72 +
28.73 + for (unsigned int j = 0; j < segments(); j++)
28.74 + _segments[j] = NULL;
28.75 + }
28.76 +
28.77 + Segment *segment = _segments[i];
28.78 +
28.79 + if (segment == NULL)
28.80 + {
28.81 + segment = new ProgramSegmentVariant<PROGRAM_HEADER>(
28.82 + (PROGRAM_HEADER *) ((char *) _header + _header->e_phoff +
28.83 + _header->e_phentsize * i));
28.84 + _segments[i] = segment;
28.85 + }
28.86 +
28.87 + return segment;
28.88 }
28.89
28.90
28.91
28.92 /* Return the appropriate payload object. */
28.93
28.94 -Payload *get_payload(char *buf)
28.95 +Payload *exec_open_payload(char *buf)
28.96 {
28.97 switch (buf[EI_CLASS])
28.98 {
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/libexec/lib/src/external_pager.cc Wed Aug 10 00:25:44 2022 +0200
29.3 @@ -0,0 +1,265 @@
29.4 +/*
29.5 + * A system pager implementation residing in a separate task.
29.6 + *
29.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
29.8 + *
29.9 + * This program is free software; you can redistribute it and/or
29.10 + * modify it under the terms of the GNU General Public License as
29.11 + * published by the Free Software Foundation; either version 2 of
29.12 + * the License, or (at your option) any later version.
29.13 + *
29.14 + * This program is distributed in the hope that it will be useful,
29.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
29.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29.17 + * GNU General Public License for more details.
29.18 + *
29.19 + * You should have received a copy of the GNU General Public License
29.20 + * along with this program; if not, write to the Free Software
29.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
29.22 + * Boston, MA 02110-1301, USA
29.23 + */
29.24 +
29.25 +#include <l4/re/env.h>
29.26 +#include <l4/sys/err.h>
29.27 +#include <l4/util/util.h>
29.28 +
29.29 +#include <ipc/mem_ipc.h>
29.30 +#include <mem/memory_utils.h>
29.31 +
29.32 +#include <stdio.h>
29.33 +#include <string.h>
29.34 +
29.35 +#include "external_pager.h"
29.36 +
29.37 +
29.38 +
29.39 +/* A simple system pager also acting as a region mapper. */
29.40 +
29.41 +/* Add a region to the pager. */
29.42 +
29.43 +void ExternalPager::add(MappedRegion ®ion)
29.44 +{
29.45 + _regions[region.map_start] = region;
29.46 +}
29.47 +
29.48 +/* Handle a general exception. */
29.49 +
29.50 +long ExternalPager::exception(l4_exc_regs_t regs, l4_snd_fpage_t *region)
29.51 +{
29.52 + (void) region;
29.53 +
29.54 + printf("exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(®s), l4_utcb_exc_pc(®s));
29.55 +
29.56 + printf("r15 = %lx\n", regs.r15);
29.57 + printf("r14 = %lx\n", regs.r14);
29.58 + printf("r13 = %lx\n", regs.r13);
29.59 + printf("r12 = %lx\n", regs.r12);
29.60 + printf("r11 = %lx\n", regs.r11);
29.61 + printf("r10 = %lx\n", regs.r10);
29.62 + printf("r9 = %lx\n", regs.r9);
29.63 + printf("r8 = %lx\n", regs.r8);
29.64 + printf("rdi = %lx\n", regs.rdi);
29.65 + printf("rsi = %lx\n", regs.rsi);
29.66 + printf("rbp = %lx\n", regs.rbp);
29.67 + printf("pfa = %lx\n", regs.pfa);
29.68 + printf("rbx = %lx\n", regs.rbx);
29.69 + printf("rdx = %lx\n", regs.rdx);
29.70 + printf("rcx = %lx\n", regs.rcx);
29.71 + printf("rax = %lx\n", regs.rax);
29.72 + printf("trapno = %lx\n", regs.trapno);
29.73 + printf("err = %lx\n", regs.err);
29.74 + printf("ip = %lx\n", regs.ip);
29.75 + printf("flags = %lx\n", regs.flags);
29.76 + printf("sp = %lx\n", regs.sp);
29.77 + printf("ss = %lx\n", regs.ss);
29.78 + printf("fs_base = %lx\n", regs.fs_base);
29.79 + printf("gs_base = %lx\n", regs.gs_base);
29.80 +
29.81 + while (1)
29.82 + l4_sleep_forever();
29.83 +
29.84 + return L4_EOK;
29.85 +}
29.86 +
29.87 +#define DEBUG 0
29.88 +
29.89 +/* Handle a page fault using any configured regions. */
29.90 +
29.91 +long ExternalPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region)
29.92 +{
29.93 + l4_umword_t addr = pfa & ~7UL, flags = pfa & 7;
29.94 +
29.95 +#if DEBUG
29.96 + printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags);
29.97 +#endif
29.98 +
29.99 + MappedRegions::iterator it = _regions.upper_bound(addr);
29.100 +
29.101 + if (it != _regions.begin())
29.102 + it--;
29.103 + else
29.104 + {
29.105 + printf("not mapped!\n");
29.106 + return -L4_ENOMEM;
29.107 + }
29.108 +
29.109 + MappedRegion &r = it->second;
29.110 +
29.111 + if ((addr >= r.map_start) && (addr < r.map_start + r.size))
29.112 + {
29.113 + l4_addr_t page_addr = trunc(addr, L4_PAGESIZE);
29.114 + 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);
29.115 +
29.116 + if (!map_flags)
29.117 + map_flags = L4RE_DS_F_R;
29.118 +
29.119 + region->fpage = l4_fpage(r.start + (page_addr - r.map_start), L4_PAGESHIFT, map_flags & r.flags);
29.120 + region->snd_base = page_addr;
29.121 +
29.122 +#if DEBUG
29.123 + printf("%lx...%lx from %lx...%lx offset %lx size %d rights %x ds %lx\n",
29.124 + r.map_start, region->snd_base,
29.125 + r.start, l4_fpage_memaddr(region->fpage),
29.126 + addr - r.map_start,
29.127 + l4_fpage_size(region->fpage),
29.128 + l4_fpage_rights(region->fpage),
29.129 + r.ds);
29.130 +
29.131 + printf("%lx -> ", addr);
29.132 +
29.133 + for (unsigned int i = 0; i < sizeof(l4_umword_t); i++)
29.134 + printf("%02x", *((unsigned char *)(r.start + (addr - r.map_start) + i)));
29.135 +
29.136 + printf("\n");
29.137 +#endif
29.138 +
29.139 + if (r.flags & L4RE_RM_F_W)
29.140 + l4_touch_rw((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE);
29.141 + else
29.142 + l4_touch_ro((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE);
29.143 +
29.144 + return L4_EOK;
29.145 + }
29.146 +
29.147 +#if DEBUG
29.148 + printf("not mapped!\n");
29.149 +#endif
29.150 +
29.151 + return -L4_ENOMEM;
29.152 +}
29.153 +
29.154 +/* Attach a region for provision when page faults occur. This is required in
29.155 + the initialisation of a program by the C library which requires a region
29.156 + mapper. */
29.157 +
29.158 +long ExternalPager::attach(address_t *start, offset_t size, map_flags_t flags,
29.159 + l4_cap_idx_t ds, address_t offset,
29.160 + unsigned char align)
29.161 +{
29.162 +#if DEBUG
29.163 + printf("attach(%lx, %ld, %lx, ..., %lx, %d)\n", *start, size, flags, offset, align);
29.164 +#endif
29.165 +
29.166 + if (align < L4_PAGESHIFT)
29.167 + align = L4_PAGESHIFT;
29.168 +
29.169 + offset_t increment = 1UL << align;
29.170 + offset_t region_size = round(size, increment);
29.171 +
29.172 + /* Either attempt to find an address for the specified region, starting from
29.173 + any indicated address. */
29.174 +
29.175 + if (flags & L4RE_RM_F_SEARCH_ADDR)
29.176 + {
29.177 + address_t region_start = trunc(*start, increment);
29.178 + MappedRegions::iterator it = _regions.upper_bound(*start);
29.179 +
29.180 + if (!region_start)
29.181 + region_start += increment;
29.182 +
29.183 +#if DEBUG
29.184 + printf("-> search from %lx -> %lx...\n", *start, region_start);
29.185 +#endif
29.186 +
29.187 + /* Before last known region. */
29.188 +
29.189 + while (it != _regions.end())
29.190 + {
29.191 + MappedRegions::iterator next = it;
29.192 + MappedRegion &r = it->second;
29.193 + address_t start_limit;
29.194 + address_t end_limit = r.map_start;
29.195 +
29.196 + /* Consider any preceding region. If no such region exists, choose an
29.197 + address at the start of memory. */
29.198 +
29.199 + if (it == _regions.begin())
29.200 + start_limit = L4_PAGESIZE;
29.201 + else
29.202 + {
29.203 + it--;
29.204 + MappedRegion &pr = it->second;
29.205 + start_limit = pr.map_start + pr.size;
29.206 + it = next;
29.207 + }
29.208 +
29.209 + /* Test against the limits. */
29.210 +
29.211 + if (region_start < start_limit)
29.212 + region_start = round(start_limit, increment);
29.213 +
29.214 + /* Investigate subsequent regions if not enough space exists between the
29.215 + preceding region (or start of memory) and the current region. */
29.216 +
29.217 + if ((region_start + region_size) > end_limit)
29.218 + {
29.219 + it++;
29.220 + if (it == _regions.end())
29.221 + return -L4_ENOMEM;
29.222 + }
29.223 + else
29.224 + break;
29.225 + }
29.226 +
29.227 + /* Attach the provided dataspace.
29.228 + NOTE: This is only done in this implementation to support the paging
29.229 + mechanism. In a region mapper residing within the actual task, the
29.230 + dataspace's map operation would be invoked to obtain mappings. */
29.231 +
29.232 + l4_addr_t ds_start;
29.233 +
29.234 + long err = ipc_attach_dataspace(ds, size, (void **) &ds_start);
29.235 +
29.236 + if (err)
29.237 + return err;
29.238 +
29.239 + l4_touch_rw((const void *) ds_start, size);
29.240 +
29.241 +#if DEBUG
29.242 + printf("-> added region at %lx size %ld (%d) from %lx ds %lx\n", region_start, region_size, page_order(region_size), ds_start, ds);
29.243 +#endif
29.244 +
29.245 + MappedRegion r(ds_start, region_size, flags & L4RE_DS_F_RIGHTS_MASK, region_start, ds);
29.246 +
29.247 + add(r);
29.248 +
29.249 + *start = region_start;
29.250 + return L4_EOK;
29.251 + }
29.252 +
29.253 + /* Or attempt to add the specified region at a specific address. */
29.254 +
29.255 + else
29.256 + {
29.257 + // NOTE: To be implemented.
29.258 +
29.259 +#if DEBUG
29.260 + printf("-> region of size %ld (%d) not added!\n", region_size, page_order(region_size));
29.261 +#endif
29.262 +
29.263 + return -L4_ENOMEM;
29.264 + }
29.265 +}
29.266 +
29.267 +/* vim: tabstop=2 expandtab shiftwidth=2
29.268 +*/
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
30.2 +++ b/libexec/lib/src/internal_pager.cc Wed Aug 10 00:25:44 2022 +0200
30.3 @@ -0,0 +1,250 @@
30.4 +/*
30.5 + * A system pager implementation residing in the same task as a program.
30.6 + *
30.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
30.8 + *
30.9 + * This program is free software; you can redistribute it and/or
30.10 + * modify it under the terms of the GNU General Public License as
30.11 + * published by the Free Software Foundation; either version 2 of
30.12 + * the License, or (at your option) any later version.
30.13 + *
30.14 + * This program is distributed in the hope that it will be useful,
30.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
30.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30.17 + * GNU General Public License for more details.
30.18 + *
30.19 + * You should have received a copy of the GNU General Public License
30.20 + * along with this program; if not, write to the Free Software
30.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
30.22 + * Boston, MA 02110-1301, USA
30.23 + */
30.24 +
30.25 +#include <l4/re/env.h>
30.26 +#include <l4/sys/err.h>
30.27 +#include <l4/util/util.h>
30.28 +
30.29 +#include <ipc/mem_ipc.h>
30.30 +#include <mem/memory_utils.h>
30.31 +
30.32 +#include <stdio.h>
30.33 +#include <string.h>
30.34 +
30.35 +#include "dataspace_client.h"
30.36 +#include "internal_pager.h"
30.37 +
30.38 +
30.39 +
30.40 +/* A simple system pager also acting as a region mapper. */
30.41 +
30.42 +/* Add a region to the pager. */
30.43 +
30.44 +void InternalPager::add(ExecRegion ®ion)
30.45 +{
30.46 + _regions[region.start] = region;
30.47 +}
30.48 +
30.49 +/* Handle a general exception. */
30.50 +
30.51 +long InternalPager::exception(l4_exc_regs_t regs, l4_snd_fpage_t *region)
30.52 +{
30.53 + (void) region;
30.54 +
30.55 + printf("exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(®s), l4_utcb_exc_pc(®s));
30.56 +
30.57 + printf("r15 = %lx\n", regs.r15);
30.58 + printf("r14 = %lx\n", regs.r14);
30.59 + printf("r13 = %lx\n", regs.r13);
30.60 + printf("r12 = %lx\n", regs.r12);
30.61 + printf("r11 = %lx\n", regs.r11);
30.62 + printf("r10 = %lx\n", regs.r10);
30.63 + printf("r9 = %lx\n", regs.r9);
30.64 + printf("r8 = %lx\n", regs.r8);
30.65 + printf("rdi = %lx\n", regs.rdi);
30.66 + printf("rsi = %lx\n", regs.rsi);
30.67 + printf("rbp = %lx\n", regs.rbp);
30.68 + printf("pfa = %lx\n", regs.pfa);
30.69 + printf("rbx = %lx\n", regs.rbx);
30.70 + printf("rdx = %lx\n", regs.rdx);
30.71 + printf("rcx = %lx\n", regs.rcx);
30.72 + printf("rax = %lx\n", regs.rax);
30.73 + printf("trapno = %lx\n", regs.trapno);
30.74 + printf("err = %lx\n", regs.err);
30.75 + printf("ip = %lx\n", regs.ip);
30.76 + printf("flags = %lx\n", regs.flags);
30.77 + printf("sp = %lx\n", regs.sp);
30.78 + printf("ss = %lx\n", regs.ss);
30.79 + printf("fs_base = %lx\n", regs.fs_base);
30.80 + printf("gs_base = %lx\n", regs.gs_base);
30.81 +
30.82 + while (1)
30.83 + l4_sleep_forever();
30.84 +
30.85 + return L4_EOK;
30.86 +}
30.87 +
30.88 +#define DEBUG 0
30.89 +
30.90 +/* Handle a page fault using any configured regions. */
30.91 +
30.92 +long InternalPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region)
30.93 +{
30.94 + l4_umword_t addr = pfa & ~7UL, flags = pfa & 7;
30.95 +
30.96 +#if DEBUG
30.97 + printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags);
30.98 +#endif
30.99 +
30.100 + ExecRegions::iterator it = _regions.upper_bound(addr);
30.101 +
30.102 + if (it != _regions.begin())
30.103 + it--;
30.104 + else
30.105 + {
30.106 + printf("not mapped!\n");
30.107 + return -L4_ENOMEM;
30.108 + }
30.109 +
30.110 + ExecRegion &r = it->second;
30.111 +
30.112 + if ((addr >= r.start) && (addr < r.start + r.size))
30.113 + {
30.114 + offset_t window_size = L4_PAGESIZE;
30.115 + address_t window_base = trunc(addr, window_size);
30.116 + offset_t offset = addr - r.start;
30.117 + address_t page_addr = trunc(addr, L4_PAGESIZE);
30.118 + address_t hot_spot = page_addr - window_base;
30.119 +
30.120 + /* Interact with the region's dataspace, specifying a receive window for a
30.121 + map operation. Here, a single page is specified. */
30.122 +
30.123 + client_Dataspace dataspace(r.ds);
30.124 + l4_snd_fpage_t rw_region = {0, l4_fpage(window_base, L4_PAGESHIFT, 0)};
30.125 + 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);
30.126 +
30.127 + if (!map_flags)
30.128 + map_flags = L4RE_DS_F_R;
30.129 +
30.130 +#if DEBUG
30.131 + printf("window_base = %lx; window_size = %lx\n", window_base, window_size);
30.132 + printf("region = {%lx, {%lx, %d}}\n", rw_region.snd_base, l4_fpage_memaddr(rw_region.fpage), l4_fpage_size(rw_region.fpage));
30.133 + printf("map(%lx, %lx, %lx) -> %lx\n", offset, hot_spot, map_flags, r.ds);
30.134 +#endif
30.135 +
30.136 + long err = dataspace.map(offset, hot_spot, map_flags & r.flags, &rw_region);
30.137 +
30.138 + /* Indicate an unspecified result, since the mapping should have taken
30.139 + place. */
30.140 +
30.141 + *region = {0, l4_fpage_invalid()};
30.142 +
30.143 + return err;
30.144 + }
30.145 +
30.146 +#if DEBUG
30.147 + printf("not mapped!\n");
30.148 +#endif
30.149 +
30.150 + return -L4_ENOMEM;
30.151 +}
30.152 +
30.153 +/* Attach a region for provision when page faults occur. This is required in
30.154 + the initialisation of a program by the C library which requires a region
30.155 + mapper. */
30.156 +
30.157 +long InternalPager::attach(address_t *start, offset_t size, map_flags_t flags,
30.158 + l4_cap_idx_t ds, address_t offset,
30.159 + unsigned char align)
30.160 +{
30.161 +#if DEBUG
30.162 + printf("attach(%lx, %ld, %lx, ..., %lx, %d)\n", *start, size, flags, offset, align);
30.163 +#endif
30.164 +
30.165 + if (align < L4_PAGESHIFT)
30.166 + align = L4_PAGESHIFT;
30.167 +
30.168 + offset_t increment = 1UL << align;
30.169 + offset_t region_size = round(size, increment);
30.170 +
30.171 + /* Either attempt to find an address for the specified region, starting from
30.172 + any indicated address. */
30.173 +
30.174 + if (flags & L4RE_RM_F_SEARCH_ADDR)
30.175 + {
30.176 + address_t region_start = trunc(*start, increment);
30.177 + ExecRegions::iterator it = _regions.upper_bound(*start);
30.178 +
30.179 + if (!region_start)
30.180 + region_start += increment;
30.181 +
30.182 +#if DEBUG
30.183 + printf("-> search from %lx -> %lx...\n", *start, region_start);
30.184 +#endif
30.185 +
30.186 + /* Before last known region. */
30.187 +
30.188 + while (it != _regions.end())
30.189 + {
30.190 + ExecRegions::iterator next = it;
30.191 + ExecRegion &r = it->second;
30.192 + address_t start_limit;
30.193 + address_t end_limit = r.start;
30.194 +
30.195 + /* Consider any preceding region. If no such region exists, choose an
30.196 + address at the start of memory. */
30.197 +
30.198 + if (it == _regions.begin())
30.199 + start_limit = L4_PAGESIZE;
30.200 + else
30.201 + {
30.202 + it--;
30.203 + ExecRegion &pr = it->second;
30.204 + start_limit = pr.start + pr.size;
30.205 + it = next;
30.206 + }
30.207 +
30.208 + /* Test against the limits. */
30.209 +
30.210 + if (region_start < start_limit)
30.211 + region_start = round(start_limit, increment);
30.212 +
30.213 + /* Investigate subsequent regions if not enough space exists between the
30.214 + preceding region (or start of memory) and the current region. */
30.215 +
30.216 + if ((region_start + region_size) > end_limit)
30.217 + {
30.218 + it++;
30.219 + if (it == _regions.end())
30.220 + return -L4_ENOMEM;
30.221 + }
30.222 + else
30.223 + break;
30.224 + }
30.225 +
30.226 +#if DEBUG
30.227 + printf("-> added region at %lx size %ld (%d) ds %lx\n", region_start, region_size, page_order(region_size), ds);
30.228 +#endif
30.229 +
30.230 + ExecRegion r = (ExecRegion) {region_start, region_size, flags & L4RE_DS_F_RIGHTS_MASK, ds};
30.231 +
30.232 + add(r);
30.233 +
30.234 + *start = region_start;
30.235 + return L4_EOK;
30.236 + }
30.237 +
30.238 + /* Or attempt to add the specified region at a specific address. */
30.239 +
30.240 + else
30.241 + {
30.242 + // NOTE: To be implemented.
30.243 +
30.244 +#if DEBUG
30.245 + printf("-> region of size %ld (%d) not added!\n", region_size, page_order(region_size));
30.246 +#endif
30.247 +
30.248 + return -L4_ENOMEM;
30.249 + }
30.250 +}
30.251 +
30.252 +/* vim: tabstop=2 expandtab shiftwidth=2
30.253 +*/
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
31.2 +++ b/libexec/lib/src/memory.cc Wed Aug 10 00:25:44 2022 +0200
31.3 @@ -0,0 +1,106 @@
31.4 +/*
31.5 + * Support for initialising program memory regions in new tasks.
31.6 + *
31.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
31.8 + *
31.9 + * This program is free software; you can redistribute it and/or
31.10 + * modify it under the terms of the GNU General Public License as
31.11 + * published by the Free Software Foundation; either version 2 of
31.12 + * the License, or (at your option) any later version.
31.13 + *
31.14 + * This program is distributed in the hope that it will be useful,
31.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
31.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31.17 + * GNU General Public License for more details.
31.18 + *
31.19 + * You should have received a copy of the GNU General Public License
31.20 + * along with this program; if not, write to the Free Software
31.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
31.22 + * Boston, MA 02110-1301, USA
31.23 + */
31.24 +
31.25 +#include <l4/sys/err.h>
31.26 +#include <l4/util/elf.h>
31.27 +
31.28 +#include <fsclient/client.h>
31.29 +#include <systypes/fcntl.h>
31.30 +
31.31 +#include <string.h>
31.32 +
31.33 +#include "memory.h"
31.34 +
31.35 +
31.36 +
31.37 +/* Obtain the payload as a dataspace. */
31.38 +
31.39 +long exec_get_payload(const char *filename, Payload **payload, bool attach)
31.40 +{
31.41 + file_t *file = client_open(filename, O_RDONLY);
31.42 +
31.43 + if (file == NULL)
31.44 + return -L4_EIO;
31.45 +
31.46 + /* Obtain metadata from the file. */
31.47 +
31.48 + char *buf = (char *) client_mmap(file, 0, file->size, 0, 0, L4RE_DS_F_R);
31.49 +
31.50 + /* Test the file type indicator. */
31.51 +
31.52 + if ((file->size < EI_NIDENT) || memcmp(buf, "\x7f" "ELF", 4))
31.53 + return -L4_EINVAL;
31.54 +
31.55 + /* Attempt to get a payload object appropriate for a particular object size
31.56 + variant. */
31.57 +
31.58 + *payload = exec_open_payload(buf);
31.59 +
31.60 + if (*payload == NULL)
31.61 + return -L4_ERANGE;
31.62 +
31.63 + if ((file->size < (*payload)->header_extent()) ||
31.64 + (file->size < (*payload)->program_header_extent()))
31.65 + {
31.66 + delete *payload;
31.67 + *payload = NULL;
31.68 + return -L4_EIO;
31.69 + }
31.70 +
31.71 + /* Obtain all loadable segments. */
31.72 +
31.73 + for (unsigned int i = 0; i < (*payload)->segments(); i++)
31.74 + {
31.75 + Segment *segment = (*payload)->segment(i);
31.76 + long err;
31.77 +
31.78 + if (!segment->loadable())
31.79 + continue;
31.80 +
31.81 + if (segment->file_contents())
31.82 + {
31.83 + file_t *rfile = client_open(filename, file_opening_flags(segment->region_flags()));
31.84 +
31.85 + if (rfile == NULL)
31.86 + {
31.87 + delete *payload;
31.88 + *payload = NULL;
31.89 + return -L4_EIO;
31.90 + }
31.91 +
31.92 + err = segment->fill(rfile, attach);
31.93 + }
31.94 + else
31.95 + err = segment->allocate(attach);
31.96 +
31.97 + if (err)
31.98 + {
31.99 + delete *payload;
31.100 + *payload = NULL;
31.101 + return err;
31.102 + }
31.103 + }
31.104 +
31.105 + return L4_EOK;
31.106 +}
31.107 +
31.108 +/* vim: tabstop=2 expandtab shiftwidth=2
31.109 +*/
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
32.2 +++ b/libexec/lib/src/pager.cc Wed Aug 10 00:25:44 2022 +0200
32.3 @@ -0,0 +1,33 @@
32.4 +/*
32.5 + * A system pager interface.
32.6 + *
32.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
32.8 + *
32.9 + * This program is free software; you can redistribute it and/or
32.10 + * modify it under the terms of the GNU General Public License as
32.11 + * published by the Free Software Foundation; either version 2 of
32.12 + * the License, or (at your option) any later version.
32.13 + *
32.14 + * This program is distributed in the hope that it will be useful,
32.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
32.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32.17 + * GNU General Public License for more details.
32.18 + *
32.19 + * You should have received a copy of the GNU General Public License
32.20 + * along with this program; if not, write to the Free Software
32.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
32.22 + * Boston, MA 02110-1301, USA
32.23 + */
32.24 +
32.25 +#include "pager.h"
32.26 +
32.27 +
32.28 +
32.29 +/* Necessary virtual destructor. */
32.30 +
32.31 +ExecPager::~ExecPager()
32.32 +{
32.33 +}
32.34 +
32.35 +/* vim: tabstop=2 expandtab shiftwidth=2
32.36 +*/
33.1 --- a/libexec/lib/src/process.cc Sun Jun 12 17:10:30 2022 +0200
33.2 +++ b/libexec/lib/src/process.cc Wed Aug 10 00:25:44 2022 +0200
33.3 @@ -50,7 +50,7 @@
33.4 /* Initialise a new process, this being an abstraction for a new task with some
33.5 threads. */
33.6
33.7 -Process::Process()
33.8 +Process::Process(int reserved_threads)
33.9 {
33.10 /* Obtain UTCB area details for the task. */
33.11
33.12 @@ -61,14 +61,17 @@
33.13 /* Populate the common initial environment for the threads. */
33.14
33.15 _env.factory = L4_BASE_FACTORY_CAP;
33.16 - _env.main_thread = L4_BASE_THREAD_CAP;
33.17 _env.log = L4_BASE_LOG_CAP;
33.18 _env.scheduler = L4_BASE_SCHEDULER_CAP;
33.19 + _env.mem_alloc = L4_EXEC_MA_CAP;
33.20 + _env.utcb_area = utcb_fpage;
33.21 + _env.first_free_utcb = l4_fpage_memaddr(utcb_fpage) + reserved_threads * L4_UTCB_OFFSET;
33.22 +
33.23 + /* Capability details that are updated for each thread. */
33.24 +
33.25 + _env.main_thread = L4_BASE_THREAD_CAP;
33.26 _env.rm = L4_EXEC_RM_CAP;
33.27 - _env.mem_alloc = L4_EXEC_MA_CAP;
33.28 _env.first_free_cap = L4_EXEC_FIRST_FREE_CAP_INDEX;
33.29 - _env.utcb_area = utcb_fpage;
33.30 - _env.first_free_utcb = l4_fpage_memaddr(utcb_fpage) + L4_UTCB_OFFSET;
33.31
33.32 /* Populate auxiliary information. */
33.33
33.34 @@ -77,6 +80,13 @@
33.35 _aux.ldr_flags = 0;
33.36 }
33.37
33.38 +/* Capability index allocation. */
33.39 +
33.40 +l4_cap_idx_t Process::allocate_cap()
33.41 +{
33.42 + return (_env.first_free_cap++ << L4_CAP_SHIFT);
33.43 +}
33.44 +
33.45 /* Task and thread initialisation. */
33.46
33.47 long Process::create_task()
33.48 @@ -101,7 +111,7 @@
33.49
33.50 /* Configure the task environment. */
33.51
33.52 -long Process::configure(l4_cap_idx_t server)
33.53 +long Process::configure_task()
33.54 {
33.55 long err = create_task();
33.56
33.57 @@ -122,17 +132,48 @@
33.58 /* Define capability mappings for the new task. */
33.59
33.60 struct ipc_mapped_cap mapped_caps[] = {
33.61 - {L4_BASE_TASK_CAP, _task, L4_CAP_FPAGE_RWS},
33.62 - {L4_EXEC_PAGER_CAP, server, L4_CAP_FPAGE_RWS},
33.63 - {_env.rm, server, L4_CAP_FPAGE_RWS},
33.64 - {_env.factory, l4re_env()->factory, L4_CAP_FPAGE_RWS},
33.65 - {_env.log, l4re_env()->log, L4_CAP_FPAGE_RWS},
33.66 - {_env.scheduler, l4re_env()->scheduler, L4_CAP_FPAGE_RWS},
33.67 - {_env.mem_alloc, l4re_env()->mem_alloc, L4_CAP_FPAGE_RWS},
33.68 - {0, L4_INVALID_CAP, 0},
33.69 + {L4_BASE_TASK_CAP, _task, L4_CAP_FPAGE_RWS, 0},
33.70 + {_env.factory, l4re_env()->factory, L4_CAP_FPAGE_RWS, 0},
33.71 + {_env.log, l4re_env()->log, L4_CAP_FPAGE_RWS, 0},
33.72 + {_env.scheduler, l4re_env()->scheduler, L4_CAP_FPAGE_RWS, 0},
33.73 + {_env.mem_alloc, l4re_env()->mem_alloc, L4_CAP_FPAGE_RWS, 0},
33.74 + {0, L4_INVALID_CAP, 0, 0},
33.75 };
33.76
33.77 - return ipc_map_capabilities(_task, mapped_caps);
33.78 + return map_capabilities(mapped_caps, false);
33.79 +}
33.80 +
33.81 +/* Configure the thread environment. */
33.82 +
33.83 +long Process::configure_thread(l4_cap_idx_t server, l4_cap_idx_t mapped_cap)
33.84 +{
33.85 + /* Employ a distinct region mapper for each thread's environment, this acting
33.86 + as pager. */
33.87 +
33.88 + if (l4_is_valid_cap(mapped_cap))
33.89 + {
33.90 + _env.rm = mapped_cap;
33.91 + return L4_EOK;
33.92 + }
33.93 + else
33.94 + {
33.95 + _env.rm = allocate_cap();
33.96 + return ipc_map_capability(_task, (struct ipc_mapped_cap) {_env.rm, server, L4_CAP_FPAGE_RWS, 0});
33.97 + }
33.98 +}
33.99 +
33.100 +/* Map capabilities into the task, counting them if indicated. */
33.101 +
33.102 +long Process::map_capabilities(struct ipc_mapped_cap mapped_caps[],
33.103 + bool to_count)
33.104 +{
33.105 + unsigned int num_mapped_caps;
33.106 + long err = ipc_map_capabilities(_task, mapped_caps, to_count ? &num_mapped_caps : NULL);
33.107 +
33.108 + if (to_count)
33.109 + _env.first_free_cap += num_mapped_caps;
33.110 +
33.111 + return err;
33.112 }
33.113
33.114 /* Create, initialise and start a thread. */
33.115 @@ -150,8 +191,8 @@
33.116 /* Initialise the thread with pager, UTCB and task details. */
33.117
33.118 l4_thread_control_start();
33.119 - l4_thread_control_pager(L4_EXEC_PAGER_CAP);
33.120 - l4_thread_control_exc_handler(L4_EXEC_PAGER_CAP);
33.121 + l4_thread_control_pager(_env.rm);
33.122 + l4_thread_control_exc_handler(_env.rm);
33.123 l4_thread_control_bind((l4_utcb_t *) _utcb_start, _task);
33.124
33.125 err = l4_error(l4_thread_control_commit(thread));
33.126 @@ -162,15 +203,24 @@
33.127 return err;
33.128 }
33.129
33.130 - /* Map the thread capability to the task. */
33.131 + /* Map the thread capability to the task using a distinct capability index. */
33.132
33.133 - ipc_map_capability(_task, (struct ipc_mapped_cap) {_env.main_thread, thread, L4_CAP_FPAGE_RWS});
33.134 + _env.main_thread = allocate_cap();
33.135 +
33.136 + ipc_map_capability(_task, (struct ipc_mapped_cap) {_env.main_thread, thread, L4_CAP_FPAGE_RWS, 0});
33.137
33.138 /* Populate the initial environment in the thread. */
33.139
33.140 st.set_l4re_aux(&_aux);
33.141 st.set_l4re_env(&_env);
33.142
33.143 + /* Reserve some extra space for capabilities used by this thread.
33.144 + NOTE: Surely the capability allocator should be able to avoid conflicts,
33.145 + but concurrency issues have been observed before, leading to various
33.146 + measures in libipc. */
33.147 +
33.148 + _env.first_free_cap += 0x20;
33.149 +
33.150 /* Set the start details. */
33.151
33.152 err = l4_error(l4_thread_ex_regs(thread, program_start, st.start_address(), 0));
34.1 --- a/libexec/lib/src/segment.cc Sun Jun 12 17:10:30 2022 +0200
34.2 +++ b/libexec/lib/src/segment.cc Wed Aug 10 00:25:44 2022 +0200
34.3 @@ -31,20 +31,29 @@
34.4
34.5
34.6
34.7 -/* Initialise a memory segment. */
34.8 +/* Obligatory destructor. */
34.9
34.10 -Segment::Segment(l4_addr_t base, offset_t size, l4re_rm_flags_t flags,
34.11 - offset_t file_offset, offset_t file_contents)
34.12 +Segment::~Segment()
34.13 +{
34.14 +}
34.15
34.16 -: _base(base), _size(size), _flags(flags), _file_offset(file_offset),
34.17 - _file_contents(file_contents)
34.18 +/* Common initialisation. */
34.19 +
34.20 +void Segment::init()
34.21 {
34.22 - _region_base = trunc(_base, L4_PAGESIZE);
34.23 - _region_offset = _base - _region_base;
34.24 + _region_base = trunc(region_address(), L4_PAGESIZE);
34.25 + _region_content_offset = region_address() - _region_base;
34.26
34.27 /* Expand the region size. */
34.28
34.29 - _region_size = round(_size + _region_offset, L4_PAGESIZE);
34.30 + _region_allocated_size = round(region_size() + _region_content_offset, L4_PAGESIZE);
34.31 +}
34.32 +
34.33 +/* Return the capability of the dataspace providing the memory. */
34.34 +
34.35 +l4_cap_idx_t Segment::cap()
34.36 +{
34.37 + return _ds;
34.38 }
34.39
34.40 /* Return the address of allocated memory. */
34.41 @@ -58,53 +67,72 @@
34.42
34.43 offset_t Segment::size()
34.44 {
34.45 - return _size;
34.46 + return _region_allocated_size;
34.47 }
34.48
34.49 /* Allocate a writable region for the segment. */
34.50
34.51 -long Segment::allocate()
34.52 +long Segment::allocate(bool attach)
34.53 {
34.54 - return ipc_allocate_align(_region_size, L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW,
34.55 - L4_PAGESHIFT, (void **) &_buf, &_ds);
34.56 + if (attach)
34.57 + return ipc_allocate_align(_region_allocated_size,
34.58 + L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW,
34.59 + L4_PAGESHIFT, (void **) &_buf, &_ds);
34.60 + else
34.61 + return ipc_new_dataspace(_region_allocated_size,
34.62 + L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW,
34.63 + L4_PAGESHIFT, &_ds);
34.64 }
34.65
34.66 /* Fill a segment region with file content. */
34.67
34.68 -long Segment::fill(file_t *file)
34.69 +long Segment::fill(file_t *file, bool attach)
34.70 {
34.71 - /* Allocate writable memory to populate. */
34.72 -
34.73 - long err = ipc_allocate_align(_region_size,
34.74 - L4RE_RM_F_SEARCH_ADDR | _flags | L4RE_RM_F_W,
34.75 - L4_PAGESHIFT, (void **) &_buf, &_ds);
34.76 -
34.77 - if (err)
34.78 - return err;
34.79 + /* Provide the exposed file contents in a masked memory mapped region, or if
34.80 + not attaching the region, merely request access via a dataspace. */
34.81
34.82 - /* Align the exposed file contents to the memory mapped region.
34.83 - Since the region is page-aligned, the region offset is introduced to map
34.84 - from an earlier part of the file, if appropriate. */
34.85 -
34.86 - memset(_buf, 0, _region_size);
34.87 + if (attach)
34.88 + {
34.89 + _buf = (char *) client_mmap(file,
34.90 + file_offset() - _region_content_offset,
34.91 + _region_allocated_size,
34.92 + file_offset(),
34.93 + file_offset() + file_contents(),
34.94 + region_flags());
34.95 + if (_buf == NULL)
34.96 + return -L4_EIO;
34.97 + }
34.98 + else
34.99 + {
34.100 + long err = file_mmap_only(file,
34.101 + file_offset() - _region_content_offset,
34.102 + _region_allocated_size,
34.103 + file_offset(),
34.104 + file_offset() + file_contents());
34.105 + if (err)
34.106 + return err;
34.107 + }
34.108
34.109 - client_seek(file, _file_offset, SEEK_SET);
34.110 - offset_t nread = client_read(file, _buf + _region_offset, _file_contents);
34.111 -
34.112 - if (nread < _file_contents)
34.113 - return -L4_EIO;
34.114 - else
34.115 - return L4_EOK;
34.116 + _ds = file->ref;
34.117 + return L4_EOK;
34.118 }
34.119
34.120 /* Define and return the mapped region for the segment. */
34.121
34.122 MappedRegion &Segment::region()
34.123 {
34.124 - _region = MappedRegion((l4_addr_t) _buf, _region_size, _flags, _region_base);
34.125 + _region = MappedRegion((l4_addr_t) _buf, _region_allocated_size, region_flags(), _region_base, _ds);
34.126 return _region;
34.127 }
34.128
34.129 +/* Define and return the region dataspace details. */
34.130 +
34.131 +struct exec_region &Segment::exec_region()
34.132 +{
34.133 + _exec_region = (struct exec_region) {_region_base, _region_allocated_size, region_flags(), _ds};
34.134 + return _exec_region;
34.135 +}
34.136 +
34.137 /* Return the mapped address corresponding to the given address. */
34.138
34.139 l4_addr_t Segment::region_address(char *address)
34.140 @@ -117,16 +145,49 @@
34.141 return (address - (l4_addr_t) _buf) + _region_base;
34.142 }
34.143
34.144 +
34.145 +
34.146 +/* Initialise a memory segment using explicit parameters. */
34.147 +
34.148 +ExplicitSegment::ExplicitSegment(l4_addr_t base, offset_t size,
34.149 + l4re_rm_flags_t flags, offset_t file_offset,
34.150 + offset_t file_contents)
34.151 +: _base(base), _size(size), _flags(flags), _file_offset(file_offset),
34.152 + _file_contents(file_contents)
34.153 +{
34.154 + init();
34.155 +}
34.156 +
34.157 /* Return the amount of file content loaded into the segment. */
34.158
34.159 -offset_t Segment::file_contents()
34.160 +bool ExplicitSegment::loadable()
34.161 +{
34.162 + return false;
34.163 +}
34.164 +
34.165 +offset_t ExplicitSegment::file_contents()
34.166 {
34.167 return _file_contents;
34.168 }
34.169
34.170 +offset_t ExplicitSegment::file_offset()
34.171 +{
34.172 + return _file_offset;
34.173 +}
34.174 +
34.175 +l4_addr_t ExplicitSegment::region_address()
34.176 +{
34.177 + return _base;
34.178 +}
34.179 +
34.180 +offset_t ExplicitSegment::region_size()
34.181 +{
34.182 + return _size;
34.183 +}
34.184 +
34.185 /* Return the region flags for the segment. */
34.186
34.187 -l4re_rm_flags_t Segment::region_flags()
34.188 +l4re_rm_flags_t ExplicitSegment::region_flags()
34.189 {
34.190 return _flags;
34.191 }
35.1 --- a/libexec/lib/src/stack.cc Sun Jun 12 17:10:30 2022 +0200
35.2 +++ b/libexec/lib/src/stack.cc Wed Aug 10 00:25:44 2022 +0200
35.3 @@ -26,7 +26,6 @@
35.4
35.5 #include <mem/memory_utils.h>
35.6
35.7 -#include <stdio.h>
35.8 #include <string.h>
35.9
35.10 #include "stack.h"
35.11 @@ -39,23 +38,58 @@
35.12 : _segment(segment)
35.13 {
35.14 _element = (l4_umword_t *) (segment.address() + segment.size());
35.15 +}
35.16
35.17 - /* Add a terminator for any additional initial capabilities. */
35.18 +/* Set any additional initial capabilities. */
35.19 +
35.20 +void Stack::set_init_caps(l4re_env_cap_entry_t *entries)
35.21 +{
35.22 + _cap_entries = entries;
35.23 +}
35.24 +
35.25 +/* Set any indicated memory regions. */
35.26 +
35.27 +void Stack::set_regions(struct exec_region *regions)
35.28 +{
35.29 + _region_entries = regions;
35.30 +}
35.31
35.32 - l4re_env_cap_entry_t *entry = (l4re_env_cap_entry_t *) _element;
35.33 +/* Push any indicated memory regions. */
35.34 +
35.35 +void Stack::push_regions()
35.36 +{
35.37 + struct exec_region *region = (struct exec_region *) _element;
35.38 + struct exec_region *regions = _region_entries;
35.39 +
35.40 + /* Terminate the regions with a null entry. */
35.41
35.42 - *(--entry) = l4re_env_cap_entry_t();
35.43 - _element = (l4_umword_t *) entry;
35.44 + *(--region) = (struct exec_region) {0, 0, 0, L4_INVALID_CAP};
35.45 +
35.46 + for (; (regions != NULL) && (regions->ds != L4_INVALID_CAP); regions++)
35.47 + {
35.48 + *(--region) = *regions;
35.49 + }
35.50 +
35.51 + _regions = (l4_addr_t) region;
35.52 + _element = (l4_umword_t *) region;
35.53 }
35.54
35.55 /* Push any additional initial capabilities. */
35.56
35.57 -void Stack::push_cap_entries(l4re_env_cap_entry_t *entries)
35.58 +void Stack::push_init_caps()
35.59 {
35.60 l4re_env_cap_entry_t *entry = (l4re_env_cap_entry_t *) _element;
35.61 + l4re_env_cap_entry_t *entries = _cap_entries;
35.62
35.63 - while ((entries != NULL) && (entries->cap != L4_INVALID_CAP))
35.64 + /* Terminate the capabilities with a null entry. */
35.65 +
35.66 + *(--entry) = l4re_env_cap_entry_t();
35.67 +
35.68 + for (; (entries != NULL) && (entries->flags != ~0UL); entries++)
35.69 + {
35.70 *(--entry) = *entries;
35.71 + _num_caps++;
35.72 + }
35.73
35.74 _caps = (l4_addr_t) entry;
35.75 _element = (l4_umword_t *) entry;
35.76 @@ -102,6 +136,15 @@
35.77
35.78 void Stack::push_l4re_aux()
35.79 {
35.80 + /* Regions for the region mapper. */
35.81 +
35.82 + if (_regions)
35.83 + *(--_element) = _segment.region_address((char *) _regions);
35.84 + else
35.85 + *(--_element) = 0;
35.86 +
35.87 + /* Reserve space for the actual L4Re auxiliary structure. */
35.88 +
35.89 _aux = (l4re_aux_t *) _element;
35.90 _aux--;
35.91 _element = (l4_umword_t *) _aux;
35.92 @@ -239,6 +282,11 @@
35.93
35.94 void Stack::populate(int argc, char *argv[], char *envp[])
35.95 {
35.96 + /* Populate stack with any regions and capabilities. */
35.97 +
35.98 + push_regions();
35.99 + push_init_caps();
35.100 +
35.101 /* Populate stack with environment and argument values. */
35.102
35.103 push_env(envp);
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
36.2 +++ b/libexec/rm/Makefile Wed Aug 10 00:25:44 2022 +0200
36.3 @@ -0,0 +1,52 @@
36.4 +PKGDIR ?= ..
36.5 +L4DIR ?= $(PKGDIR)/../../..
36.6 +
36.7 +TARGET = exec_region_mapper
36.8 +
36.9 +MODE = static
36.10 +
36.11 +# Relocate the binary to avoid conflicting with actual payloads.
36.12 +
36.13 +DEFAULT_RELOC_x86 := 0xb0000000
36.14 +DEFAULT_RELOC_arm := 0xb0000000
36.15 +DEFAULT_RELOC_arm64 := 0xc0000000
36.16 +DEFAULT_RELOC_ppc32 := 0xb0000000
36.17 +DEFAULT_RELOC_amd64 := 0x70000000
36.18 +DEFAULT_RELOC_mips := 0x70000000
36.19 +
36.20 +# Locations for interface input and generated output.
36.21 +
36.22 +IDL_DIR = $(PKGDIR)/../libsystypes/idl
36.23 +IDL_MK_DIR = $(L4DIR)/idl4re/mk
36.24 +IDL_BUILD_DIR = .
36.25 +IDL_EXPORT_DIR = .
36.26 +
36.27 +include $(IDL_MK_DIR)/idl.mk
36.28 +
36.29 +# Compound interfaces.
36.30 +
36.31 +pager_object_NAME = PagerObject
36.32 +pager_object_INTERFACES = region_mapper system_pager
36.33 +
36.34 +COMP_INTERFACES_CC = pager_object
36.35 +
36.36 +# Individual interfaces.
36.37 +
36.38 +SERVER_INTERFACES_CC = $(call common_interfaces,$(COMP_INTERFACES_CC))
36.39 +
36.40 +# Generated and plain source files.
36.41 +
36.42 +SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC) $(COMP_INTERFACES_CC))
36.43 +
36.44 +# Normal source files.
36.45 +
36.46 +PLAIN_SRC_CC = region_mapper.cc
36.47 +SRC_CC = $(PLAIN_SRC_CC) $(SERVER_INTERFACES_SRC_CC)
36.48 +
36.49 +REQUIRES_LIBS = libc libstdc++ libexec libipc
36.50 +PRIVATE_INCDIR = $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR)
36.51 +
36.52 +include $(L4DIR)/mk/prog.mk
36.53 +include $(IDL_MK_DIR)/interface_rules.mk
36.54 +
36.55 +$(PLAIN_SRC_CC): $(SERVER_INTERFACES_SRC_CC)
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
37.2 +++ b/libexec/rm/region_mapper.cc Wed Aug 10 00:25:44 2022 +0200
37.3 @@ -0,0 +1,75 @@
37.4 +/*
37.5 + * A region mapper for deployment in a new task.
37.6 + *
37.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
37.8 + *
37.9 + * This program is free software; you can redistribute it and/or
37.10 + * modify it under the terms of the GNU General Public License as
37.11 + * published by the Free Software Foundation; either version 2 of
37.12 + * the License, or (at your option) any later version.
37.13 + *
37.14 + * This program is distributed in the hope that it will be useful,
37.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
37.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37.17 + * GNU General Public License for more details.
37.18 + *
37.19 + * You should have received a copy of the GNU General Public License
37.20 + * along with this program; if not, write to the Free Software
37.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
37.22 + * Boston, MA 02110-1301, USA
37.23 + */
37.24 +
37.25 +#include <l4/re/env.h>
37.26 +
37.27 +#include <exec/common.h>
37.28 +#include <exec/internal_pager.h>
37.29 +#include <exec/stack.h>
37.30 +#include <ipc/server.h>
37.31 +
37.32 +#include "pager_object_server.h"
37.33 +
37.34 +
37.35 +
37.36 +static InternalPager exec_pager;
37.37 +
37.38 +
37.39 +
37.40 +int main(int argc, char *argv[])
37.41 +{
37.42 + /* Initialise pager regions from region descriptions obtained via the
37.43 + auxiliary data. */
37.44 +
37.45 + l4re_aux_t *l4re_aux = exec_get_l4re_aux(argc, argv);
37.46 +
37.47 + printf("aux = {%s, %lx, %lx, %lx}\n", l4re_aux->binary, l4re_aux->kip_ds, l4re_aux->dbg_lvl, l4re_aux->ldr_flags);
37.48 +
37.49 + /* Skip past the auxiliary structure itself. */
37.50 +
37.51 + struct exec_region *region = (struct exec_region *) *((l4_addr_t *) (l4re_aux + 1));
37.52 +
37.53 + if (!region)
37.54 + {
37.55 + printf("Could not find regions.\n");
37.56 + return 1;
37.57 + }
37.58 +
37.59 + for (; region && (region->ds != L4_INVALID_CAP); region++)
37.60 + {
37.61 + printf("Adding region: {%lx, %lx, %lx, %lx}\n", region->start, region->size, region->flags, region->ds);
37.62 + exec_pager.add(*region);
37.63 + }
37.64 +
37.65 + /* Start the pager. */
37.66 +
37.67 + printf("Starting pager...\n");
37.68 + printf("Pager capability: %lx\n", l4re_env_get_cap("server"));
37.69 + printf("Main thread: %lx\n", l4re_env()->main_thread);
37.70 +
37.71 + ipc_server_loop_for(PagerObject, &exec_pager, "server");
37.72 +
37.73 + printf("Ending pager...\n");
37.74 + return 0;
37.75 +}
37.76 +
37.77 +/* vim: tabstop=2 expandtab shiftwidth=2
37.78 +*/
38.1 --- a/libfsclient/include/fsclient/client.h Sun Jun 12 17:10:30 2022 +0200
38.2 +++ b/libfsclient/include/fsclient/client.h Wed Aug 10 00:25:44 2022 +0200
38.3 @@ -64,7 +64,10 @@
38.4 /* File and region operations. */
38.5
38.6 long client_flush(file_t *file);
38.7 -void *client_mmap(file_t *file, offset_t position, offset_t length);
38.8 +void *client_mmap(file_t *file, offset_t position, offset_t length,
38.9 + offset_t start_visible, offset_t end_visible,
38.10 + l4re_rm_flags_t region_flags);
38.11 +l4re_rm_flags_t client_region_flags(prot_t prot, flags_t flags);
38.12
38.13 /* Pipe region operations. */
38.14
39.1 --- a/libfsclient/include/fsclient/file.h Sun Jun 12 17:10:30 2022 +0200
39.2 +++ b/libfsclient/include/fsclient/file.h Wed Aug 10 00:25:44 2022 +0200
39.3 @@ -23,6 +23,7 @@
39.4
39.5 #include <sys/stat.h>
39.6
39.7 +#include <l4/re/c/rm.h>
39.8 #include <l4/sys/types.h>
39.9
39.10 #include <systypes/base.h>
39.11 @@ -74,6 +75,10 @@
39.12
39.13 notify_flags_t notifications;
39.14
39.15 + /* Flags indicated when opening the file. */
39.16 +
39.17 + flags_t flags;
39.18 +
39.19 } file_t;
39.20
39.21
39.22 @@ -104,7 +109,13 @@
39.23 /* File and region operations. */
39.24
39.25 long file_flush(file_t *file);
39.26 -long file_mmap(file_t *file, offset_t position, offset_t length);
39.27 +long file_mmap(file_t *file, offset_t position, offset_t length,
39.28 + offset_t start_visible, offset_t end_visible,
39.29 + l4re_rm_flags_t region_flags);
39.30 +long file_mmap_only(file_t *file, offset_t position, offset_t length,
39.31 + offset_t start_visible, offset_t end_visible);
39.32 +flags_t file_opening_flags(l4re_rm_flags_t rm_flags);
39.33 +l4re_rm_flags_t file_region_flags(flags_t flags);
39.34 long file_resize(file_t *file, offset_t size);
39.35
39.36 /* File and region properties. */
40.1 --- a/libfsclient/lib/src/client.cc Sun Jun 12 17:10:30 2022 +0200
40.2 +++ b/libfsclient/lib/src/client.cc Wed Aug 10 00:25:44 2022 +0200
40.3 @@ -41,6 +41,32 @@
40.4
40.5
40.6
40.7 +/* Merging of region flags from protection and access flags. */
40.8 +
40.9 +static l4re_rm_flags_t _combine_region_flags(l4re_rm_flags_t region_flags,
40.10 + flags_t flags)
40.11 +{
40.12 + return region_flags & (file_region_flags(flags) | L4RE_RM_F_X);
40.13 +}
40.14 +
40.15 +/* Conversion of protection and access flags to region flags. */
40.16 +
40.17 +l4re_rm_flags_t client_region_flags(prot_t prot, flags_t flags)
40.18 +{
40.19 + l4re_rm_flags_t rm_flags = 0;
40.20 +
40.21 + if (prot & PROT_READ)
40.22 + rm_flags |= L4RE_RM_F_R;
40.23 + if (prot & PROT_WRITE)
40.24 + rm_flags |= L4RE_RM_F_W;
40.25 + if (prot & PROT_EXEC)
40.26 + rm_flags |= L4RE_RM_F_X;
40.27 +
40.28 + return _combine_region_flags(rm_flags, flags);
40.29 +}
40.30 +
40.31 +
40.32 +
40.33 /* Access the given position and synchronise state with the file object. Pipe
40.34 objects may return busy conditions indicating that the desired access cannot
40.35 yet be fulfilled. */
40.36 @@ -55,7 +81,8 @@
40.37
40.38 if ((position < file->start_pos) || (position >= file->end_pos))
40.39 {
40.40 - if (file_mmap(file, position, file_span(file)))
40.41 + if (file_mmap(file, position, file_span(file), 0, 0,
40.42 + file_region_flags(file->flags)))
40.43 return -L4_EIO;
40.44 }
40.45
40.46 @@ -164,7 +191,8 @@
40.47 if (file->memory == NULL)
40.48 {
40.49 if (file->object_flags & OBJECT_SUPPORTS_MMAP)
40.50 - return client_mmap(file, client_tell(file), count);
40.51 + return client_mmap(file, client_tell(file), count, 0, 0,
40.52 + file_region_flags(file->flags));
40.53 else if (pipe_current(file))
40.54 return NULL;
40.55 }
40.56 @@ -459,9 +487,12 @@
40.57
40.58 /* Map a memory region to a file. */
40.59
40.60 -void *client_mmap(file_t *file, offset_t position, offset_t length)
40.61 +void *client_mmap(file_t *file, offset_t position, offset_t length,
40.62 + offset_t start_visible, offset_t end_visible,
40.63 + l4re_rm_flags_t region_flags)
40.64 {
40.65 - if ((file == NULL) || (file_mmap(file, position, length)))
40.66 + if ((file == NULL) || file_mmap(file, position, length, start_visible,
40.67 + end_visible, region_flags))
40.68 return NULL;
40.69
40.70 return file->memory;
41.1 --- a/libfsclient/lib/src/file.cc Sun Jun 12 17:10:30 2022 +0200
41.2 +++ b/libfsclient/lib/src/file.cc Wed Aug 10 00:25:44 2022 +0200
41.3 @@ -21,8 +21,10 @@
41.4
41.5 #include <ipc/cap_alloc.h>
41.6 #include <ipc/mem_ipc.h>
41.7 +#include <systypes/fcntl.h>
41.8 #include <systypes/stat.h>
41.9
41.10 +#include <stdio.h>
41.11 #include <string.h>
41.12
41.13 #include "dataspace_client.h"
41.14 @@ -88,6 +90,7 @@
41.15 file->object_flags = 0;
41.16 file->can_block = 0;
41.17 file->notifications = 0;
41.18 + file->flags = 0;
41.19 }
41.20
41.21
41.22 @@ -255,6 +258,7 @@
41.23 long err;
41.24
41.25 file_init(file);
41.26 + file->flags = O_RDWR;
41.27
41.28 err = opener.context(&file->ref);
41.29 if (err)
41.30 @@ -286,6 +290,7 @@
41.31 {
41.32 client_OpenerContext openercontext(context->ref);
41.33 file_init(file);
41.34 + file->flags = flags;
41.35 return openercontext.open(flags, &file->size, &file->ref, &file->object_flags);
41.36 }
41.37
41.38 @@ -346,19 +351,20 @@
41.39 /* Map a region of the given file to a memory region, obtaining an updated file
41.40 size and populated data details. Unmap any previously mapped region. */
41.41
41.42 -long file_mmap(file_t *file, offset_t position, offset_t length)
41.43 +long file_mmap(file_t *file, offset_t position, offset_t length,
41.44 + offset_t start_visible, offset_t end_visible,
41.45 + l4re_rm_flags_t region_flags)
41.46 {
41.47 char *memory = file->memory;
41.48 - client_MappedFile mapped_file(file->ref);
41.49 - long err = mapped_file.mmap(position, length, &file->start_pos,
41.50 - &file->end_pos, &file->size);
41.51 + long err = file_mmap_only(file, position, length, start_visible, end_visible);
41.52
41.53 if (err)
41.54 return err;
41.55
41.56 - _update_extent(file);
41.57 -
41.58 - err = ipc_attach_dataspace(file->ref, file_span(file), (void **) &file->memory);
41.59 + err = ipc_attach_dataspace_align(file->ref, file_span(file),
41.60 + L4RE_RM_F_SEARCH_ADDR | region_flags,
41.61 + L4_PAGESHIFT,
41.62 + (void **) &file->memory);
41.63 if (err)
41.64 return err;
41.65
41.66 @@ -368,6 +374,60 @@
41.67 return L4_EOK;
41.68 }
41.69
41.70 +/* Request access to a region of the given file, obtaining an updated file size
41.71 + and populated data details. The region is not mapped, however. */
41.72 +
41.73 +long file_mmap_only(file_t *file, offset_t position, offset_t length,
41.74 + offset_t start_visible, offset_t end_visible)
41.75 +{
41.76 + client_MappedFile mapped_file(file->ref);
41.77 + long err = mapped_file.mmap(position, length, start_visible, end_visible,
41.78 + &file->start_pos, &file->end_pos, &file->size);
41.79 +
41.80 + if (err)
41.81 + return err;
41.82 +
41.83 + _update_extent(file);
41.84 +
41.85 + return L4_EOK;
41.86 +}
41.87 +
41.88 +/* Return opening flags compatible with the given region flags. */
41.89 +
41.90 +flags_t file_opening_flags(l4re_rm_flags_t rm_flags)
41.91 +{
41.92 + if ((rm_flags & L4RE_RM_F_RW) == L4RE_RM_F_RW)
41.93 + return O_RDWR;
41.94 + else if (rm_flags & L4RE_RM_F_W)
41.95 + return O_WRONLY;
41.96 + else
41.97 + return O_RDONLY;
41.98 +}
41.99 +
41.100 +/* Return mmap flags corresponding to the file access flags. */
41.101 +
41.102 +l4re_rm_flags_t file_region_flags(flags_t flags)
41.103 +{
41.104 + l4re_rm_flags_t rm_flags;
41.105 +
41.106 + switch (flags & 3)
41.107 + {
41.108 + case O_WRONLY:
41.109 + rm_flags = L4RE_RM_F_W;
41.110 + break;
41.111 +
41.112 + case O_RDWR:
41.113 + rm_flags = L4RE_RM_F_RW;
41.114 + break;
41.115 +
41.116 + default:
41.117 + rm_flags = L4RE_RM_F_R;
41.118 + break;
41.119 + }
41.120 +
41.121 + return rm_flags;
41.122 +}
41.123 +
41.124 /* Resize a file, obtaining updated file size and populated data details. */
41.125
41.126 long file_resize(file_t *file, offset_t size)
41.127 @@ -624,6 +684,8 @@
41.128
41.129 file_init(reader);
41.130 file_init(writer);
41.131 + reader->flags = O_RDONLY;
41.132 + writer->flags = O_WRONLY;
41.133
41.134 return opener.pipe(size, &reader->ref, &writer->ref);
41.135 }
41.136 @@ -697,6 +759,7 @@
41.137 {
41.138 client_Directory directory(file->ref);
41.139 file_init(reader);
41.140 + reader->flags = O_RDONLY;
41.141 return directory.opendir(&reader->size, &reader->ref, &reader->object_flags);
41.142 }
41.143
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
42.2 +++ b/libfsserver/include/fsserver/copied_page_mapper.h Wed Aug 10 00:25:44 2022 +0200
42.3 @@ -0,0 +1,81 @@
42.4 +/*
42.5 + * A page mapper providing copied memory pages or deferring to another page
42.6 + * mapper to satisfy file accesses.
42.7 + *
42.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
42.9 + *
42.10 + * This program is free software; you can redistribute it and/or
42.11 + * modify it under the terms of the GNU General Public License as
42.12 + * published by the Free Software Foundation; either version 2 of
42.13 + * the License, or (at your option) any later version.
42.14 + *
42.15 + * This program is distributed in the hope that it will be useful,
42.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
42.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42.18 + * GNU General Public License for more details.
42.19 + *
42.20 + * You should have received a copy of the GNU General Public License
42.21 + * along with this program; if not, write to the Free Software
42.22 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
42.23 + * Boston, MA 02110-1301, USA
42.24 + */
42.25 +
42.26 +#pragma once
42.27 +
42.28 +#include <list>
42.29 +
42.30 +#include <fsserver/access_map.h>
42.31 +#include <fsserver/generic_page_mapper.h>
42.32 +#include <mem/memory_incremental.h>
42.33 +
42.34 +
42.35 +
42.36 +/* A special flexpage class for copied flexpages. */
42.37 +
42.38 +class CopiedFlexpage : public Flexpage
42.39 +{
42.40 +public:
42.41 + explicit CopiedFlexpage(Region *region = NULL);
42.42 +};
42.43 +
42.44 +
42.45 +
42.46 +/* A file mapper, associating flexpages with file regions. */
42.47 +
42.48 +class CopiedPageMapper : public GenericPageMapper
42.49 +{
42.50 +protected:
42.51 + GenericPageMapper *_mapper;
42.52 + offset_t _size;
42.53 +
42.54 + /* Copied page support. */
42.55 +
42.56 + AccessMap _map;
42.57 + MemoryIncremental _memory;
42.58 + std::list<Flexpage *> _queue;
42.59 +
42.60 + /* Internal flexpage retrieval methods. */
42.61 +
42.62 + Flexpage *find(offset_t offset);
42.63 +
42.64 + Flexpage *replicate_flexpage(offset_t offset, Flexpage *flexpage);
42.65 +
42.66 +public:
42.67 + explicit CopiedPageMapper(GenericPageMapper *mapper);
42.68 +
42.69 + virtual ~CopiedPageMapper();
42.70 +
42.71 + /* Interface for the pager, implementing GenericPageMapper. */
42.72 +
42.73 + Flexpage *get(offset_t offset, map_flags_t flags);
42.74 +
42.75 + void queue(Flexpage *flexpage);
42.76 +
42.77 + void flush_all(offset_t start, offset_t size);
42.78 +
42.79 + offset_t get_data_size();
42.80 +
42.81 + void set_data_size(offset_t size);
42.82 +};
42.83 +
42.84 +// vim: tabstop=4 expandtab shiftwidth=4
43.1 --- a/libfsserver/include/fsserver/directory_provider.h Sun Jun 12 17:10:30 2022 +0200
43.2 +++ b/libfsserver/include/fsserver/directory_provider.h Wed Aug 10 00:25:44 2022 +0200
43.3 @@ -1,7 +1,7 @@
43.4 /*
43.5 * An object providing a directory abstraction with notification facilities.
43.6 *
43.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
43.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
43.9 *
43.10 * This program is free software; you can redistribute it and/or
43.11 * modify it under the terms of the GNU General Public License as
43.12 @@ -41,7 +41,8 @@
43.13
43.14 virtual DirectoryAccessor *accessor();
43.15
43.16 - virtual long make_resource(offset_t *size, object_flags_t *object_flags,
43.17 + virtual long make_resource(flags_t flags, offset_t *size,
43.18 + object_flags_t *object_flags,
43.19 Resource **resource);
43.20 };
43.21
44.1 --- a/libfsserver/include/fsserver/file_pager.h Sun Jun 12 17:10:30 2022 +0200
44.2 +++ b/libfsserver/include/fsserver/file_pager.h Wed Aug 10 00:25:44 2022 +0200
44.3 @@ -1,7 +1,7 @@
44.4 /*
44.5 * File-specific pager functionality.
44.6 *
44.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
44.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
44.9 *
44.10 * This program is free software; you can redistribute it and/or
44.11 * modify it under the terms of the GNU General Public License as
44.12 @@ -33,6 +33,7 @@
44.13 {
44.14 protected:
44.15 FileProvider *_provider;
44.16 + flags_t _flags;
44.17
44.18 /* Notification endpoint for event subscription. */
44.19
44.20 @@ -42,10 +43,14 @@
44.21
44.22 bool _resized = false;
44.23
44.24 + /* Helper methods. */
44.25 +
44.26 + bool copy_on_write();
44.27 +
44.28 public:
44.29 fileid_t fileid;
44.30
44.31 - explicit FilePager(fileid_t fileid, FileProvider *provider, map_flags_t flags);
44.32 + explicit FilePager(fileid_t fileid, FileProvider *provider, flags_t flags);
44.33
44.34 virtual void close();
44.35
44.36 @@ -69,8 +74,9 @@
44.37 virtual long map(offset_t offset, address_t hot_spot, map_flags_t flags,
44.38 l4_snd_fpage_t *region);
44.39
44.40 - virtual long mmap(offset_t position, offset_t length, offset_t *start_pos,
44.41 - offset_t *end_pos, offset_t *size);
44.42 + virtual long mmap(offset_t position, offset_t length,
44.43 + offset_t start_visible, offset_t end_visible,
44.44 + offset_t *start_pos, offset_t *end_pos, offset_t *size);
44.45
44.46 /* Notification methods. */
44.47
45.1 --- a/libfsserver/include/fsserver/file_provider.h Sun Jun 12 17:10:30 2022 +0200
45.2 +++ b/libfsserver/include/fsserver/file_provider.h Wed Aug 10 00:25:44 2022 +0200
45.3 @@ -1,7 +1,7 @@
45.4 /*
45.5 * An object encapsulating file resources.
45.6 *
45.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
45.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
45.9 *
45.10 * This program is free software; you can redistribute it and/or
45.11 * modify it under the terms of the GNU General Public License as
45.12 @@ -31,18 +31,18 @@
45.13 class FileProvider : public Provider
45.14 {
45.15 protected:
45.16 - map_flags_t _flags;
45.17 PageMapper *_mapper;
45.18
45.19 public:
45.20 - explicit FileProvider(fileid_t fileid, map_flags_t flags,
45.21 - ProviderRegistry *registry, PageMapper *mapper);
45.22 + explicit FileProvider(fileid_t fileid, ProviderRegistry *registry,
45.23 + PageMapper *mapper);
45.24
45.25 virtual ~FileProvider();
45.26
45.27 virtual PageMapper *mapper();
45.28
45.29 - virtual long make_resource(offset_t *size, object_flags_t *object_flags,
45.30 + virtual long make_resource(flags_t flags, offset_t *size,
45.31 + object_flags_t *object_flags,
45.32 Resource **resource);
45.33
45.34 virtual void remove();
46.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
46.2 +++ b/libfsserver/include/fsserver/generic_page_mapper.h Wed Aug 10 00:25:44 2022 +0200
46.3 @@ -0,0 +1,47 @@
46.4 +/*
46.5 + * A generic page mapper providing memory pages to satisfy file accesses.
46.6 + *
46.7 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
46.8 + *
46.9 + * This program is free software; you can redistribute it and/or
46.10 + * modify it under the terms of the GNU General Public License as
46.11 + * published by the Free Software Foundation; either version 2 of
46.12 + * the License, or (at your option) any later version.
46.13 + *
46.14 + * This program is distributed in the hope that it will be useful,
46.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
46.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46.17 + * GNU General Public License for more details.
46.18 + *
46.19 + * You should have received a copy of the GNU General Public License
46.20 + * along with this program; if not, write to the Free Software
46.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
46.22 + * Boston, MA 02110-1301, USA
46.23 + */
46.24 +
46.25 +#pragma once
46.26 +
46.27 +#include <mem/flexpage.h>
46.28 +
46.29 +
46.30 +
46.31 +/* A generic file mapper interface, accessed by the pager, associating flexpages
46.32 + with file regions. */
46.33 +
46.34 +class GenericPageMapper
46.35 +{
46.36 +public:
46.37 + virtual ~GenericPageMapper();
46.38 +
46.39 + virtual Flexpage *get(offset_t offset, map_flags_t flags);
46.40 +
46.41 + virtual void queue(Flexpage *flexpage);
46.42 +
46.43 + virtual void flush_all(offset_t start, offset_t size);
46.44 +
46.45 + virtual offset_t get_data_size();
46.46 +
46.47 + virtual void set_data_size(offset_t size);
46.48 +};
46.49 +
46.50 +// vim: tabstop=4 expandtab shiftwidth=4
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
47.2 +++ b/libfsserver/include/fsserver/masked_page_mapper.h Wed Aug 10 00:25:44 2022 +0200
47.3 @@ -0,0 +1,82 @@
47.4 +/*
47.5 + * A page mapper providing memory pages to satisfy file accesses, masking the
47.6 + * limits of a visible region of the file's contents.
47.7 + *
47.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
47.9 + *
47.10 + * This program is free software; you can redistribute it and/or
47.11 + * modify it under the terms of the GNU General Public License as
47.12 + * published by the Free Software Foundation; either version 2 of
47.13 + * the License, or (at your option) any later version.
47.14 + *
47.15 + * This program is distributed in the hope that it will be useful,
47.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
47.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47.18 + * GNU General Public License for more details.
47.19 + *
47.20 + * You should have received a copy of the GNU General Public License
47.21 + * along with this program; if not, write to the Free Software
47.22 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
47.23 + * Boston, MA 02110-1301, USA
47.24 + */
47.25 +
47.26 +#pragma once
47.27 +
47.28 +#include <fsserver/generic_page_mapper.h>
47.29 +#include <mem/memory_incremental.h>
47.30 +
47.31 +
47.32 +
47.33 +/* A special flexpage class for masked flexpages. */
47.34 +
47.35 +class MaskedFlexpage : public Flexpage
47.36 +{
47.37 +public:
47.38 + explicit MaskedFlexpage(Region *region = NULL);
47.39 +};
47.40 +
47.41 +
47.42 +
47.43 +/* A file mapper, associating flexpages with file regions. */
47.44 +
47.45 +class MaskedPageMapper : public GenericPageMapper
47.46 +{
47.47 +protected:
47.48 + GenericPageMapper *_mapper;
47.49 + offset_t _size;
47.50 +
47.51 + /* Masked region support. */
47.52 +
47.53 + MemoryIncremental _memory;
47.54 + offset_t _start_visible, _end_visible;
47.55 + MaskedFlexpage _start_flexpage, _end_flexpage, _zero_flexpage;
47.56 +
47.57 + /* Internal flexpage retrieval methods. */
47.58 +
47.59 + Flexpage *get_masked_flexpage(Flexpage *flexpage);
47.60 +
47.61 + void allocate_region(Flexpage *flexpage, Flexpage &masked);
47.62 +
47.63 + void populate_region(Flexpage *flexpage, Flexpage &masked,
47.64 + bool has_start, bool has_end);
47.65 +
47.66 +public:
47.67 + explicit MaskedPageMapper(GenericPageMapper *mapper, offset_t start_visible,
47.68 + offset_t end_visible);
47.69 +
47.70 + virtual ~MaskedPageMapper();
47.71 +
47.72 + /* Interface for the pager, implementing GenericPageMapper. */
47.73 +
47.74 + Flexpage *get(offset_t offset, map_flags_t flags);
47.75 +
47.76 + void queue(Flexpage *flexpage);
47.77 +
47.78 + void flush_all(offset_t start, offset_t size);
47.79 +
47.80 + offset_t get_data_size();
47.81 +
47.82 + void set_data_size(offset_t size);
47.83 +};
47.84 +
47.85 +// vim: tabstop=4 expandtab shiftwidth=4
48.1 --- a/libfsserver/include/fsserver/page_mapper.h Sun Jun 12 17:10:30 2022 +0200
48.2 +++ b/libfsserver/include/fsserver/page_mapper.h Wed Aug 10 00:25:44 2022 +0200
48.3 @@ -1,7 +1,7 @@
48.4 /*
48.5 * A page mapper providing memory pages to satisfy file accesses.
48.6 *
48.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
48.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
48.9 *
48.10 * This program is free software; you can redistribute it and/or
48.11 * modify it under the terms of the GNU General Public License as
48.12 @@ -23,6 +23,7 @@
48.13
48.14 #include <fsserver/access_map.h>
48.15 #include <fsserver/accessor.h>
48.16 +#include <fsserver/generic_page_mapper.h>
48.17 #include <fsserver/page_owner.h>
48.18
48.19 #include <mutex>
48.20 @@ -31,7 +32,7 @@
48.21
48.22 /* A file mapper, associating flexpages with file regions. */
48.23
48.24 -class PageMapper : public PageOwner
48.25 +class PageMapper : public GenericPageMapper, public PageOwner
48.26 {
48.27 protected:
48.28 AccessMap _map;
48.29 @@ -56,7 +57,7 @@
48.30 Accessor *accessor()
48.31 { return _accessor; }
48.32
48.33 - /* Interface for the pager. */
48.34 + /* Interface for the pager, implementing GenericPageMapper. */
48.35
48.36 Flexpage *get(offset_t offset, map_flags_t flags);
48.37
49.1 --- a/libfsserver/include/fsserver/pager.h Sun Jun 12 17:10:30 2022 +0200
49.2 +++ b/libfsserver/include/fsserver/pager.h Wed Aug 10 00:25:44 2022 +0200
49.3 @@ -1,7 +1,7 @@
49.4 /*
49.5 * Generic pager functionality.
49.6 *
49.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
49.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
49.9 *
49.10 * This program is free software; you can redistribute it and/or
49.11 * modify it under the terms of the GNU General Public License as
49.12 @@ -23,7 +23,7 @@
49.13
49.14 #include <systypes/base.h>
49.15
49.16 -#include <fsserver/page_mapper.h>
49.17 +#include <fsserver/generic_page_mapper.h>
49.18 #include <fsserver/resource.h>
49.19
49.20
49.21 @@ -34,17 +34,17 @@
49.22 {
49.23 protected:
49.24 offset_t _start, _size;
49.25 - PageMapper *_mapper;
49.26 - map_flags_t _flags;
49.27 + GenericPageMapper *_mapper, *_mapper_base, *_mapper_masked, *_mapper_copied;
49.28 + map_flags_t _map_flags;
49.29
49.30 public:
49.31 - explicit Pager(PageMapper *mapper, map_flags_t flags);
49.32 + explicit Pager(GenericPageMapper *mapper, map_flags_t map_flags);
49.33
49.34 virtual void close();
49.35
49.36 /* Paging methods. */
49.37
49.38 - virtual long map(offset_t offset, address_t hot_spot, map_flags_t flags,
49.39 + virtual long map(offset_t offset, address_t hot_spot, map_flags_t map_flags,
49.40 l4_snd_fpage_t *region);
49.41
49.42 /* Limit methods. */
49.43 @@ -59,8 +59,9 @@
49.44
49.45 /* Mapped file methods. */
49.46
49.47 - virtual long mmap(offset_t position, offset_t length, offset_t *start_pos,
49.48 - offset_t *end_pos, offset_t *size);
49.49 + virtual long mmap(offset_t position, offset_t length,
49.50 + offset_t start_visible, offset_t end_visible,
49.51 + offset_t *start_pos, offset_t *end_pos, offset_t *size);
49.52 };
49.53
49.54 // vim: tabstop=4 expandtab shiftwidth=4
50.1 --- a/libfsserver/include/fsserver/pages.h Sun Jun 12 17:10:30 2022 +0200
50.2 +++ b/libfsserver/include/fsserver/pages.h Wed Aug 10 00:25:44 2022 +0200
50.3 @@ -1,7 +1,7 @@
50.4 /*
50.5 * A page collection abstraction providing pages from a queue to users.
50.6 *
50.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
50.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
50.9 *
50.10 * This program is free software; you can redistribute it and/or
50.11 * modify it under the terms of the GNU General Public License as
50.12 @@ -36,13 +36,13 @@
50.13 Memory *_memory;
50.14 PageQueue *_queue;
50.15
50.16 + virtual Flexpage *remove();
50.17 +
50.18 public:
50.19 explicit Pages(Memory *memory, PageQueue *queue);
50.20
50.21 virtual ~Pages();
50.22
50.23 - virtual Flexpage *remove();
50.24 -
50.25 virtual bool reserve(PageOwner *owner, Flexpage *flexpage);
50.26
50.27 virtual Flexpage *flexpage();
51.1 --- a/libfsserver/include/fsserver/provider.h Sun Jun 12 17:10:30 2022 +0200
51.2 +++ b/libfsserver/include/fsserver/provider.h Wed Aug 10 00:25:44 2022 +0200
51.3 @@ -1,7 +1,7 @@
51.4 /*
51.5 * Filesystem object provider support.
51.6 *
51.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
51.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
51.9 *
51.10 * This program is free software; you can redistribute it and/or
51.11 * modify it under the terms of the GNU General Public License as
51.12 @@ -44,7 +44,8 @@
51.13
51.14 virtual ProviderRegistry *registry();
51.15
51.16 - virtual long make_resource(offset_t *size, object_flags_t *object_flags,
51.17 + virtual long make_resource(flags_t flags, offset_t *size,
51.18 + object_flags_t *object_flags,
51.19 Resource **resource) = 0;
51.20
51.21 /* Lifecycle methods. */
52.1 --- a/libfsserver/lib/Makefile Sun Jun 12 17:10:30 2022 +0200
52.2 +++ b/libfsserver/lib/Makefile Wed Aug 10 00:25:44 2022 +0200
52.3 @@ -76,7 +76,10 @@
52.4 generic/resource_server.cc \
52.5 generic/simple_pager.cc \
52.6 mapping/access_map.cc \
52.7 + mapping/copied_page_mapper.cc \
52.8 + mapping/generic_page_mapper.cc \
52.9 mapping/ipc.cc \
52.10 + mapping/masked_page_mapper.cc \
52.11 mapping/page_mapper.cc \
52.12 pages/page_queue.cc \
52.13 pages/page_queue_partitioned.cc \
53.1 --- a/libfsserver/lib/directories/directory_provider.cc Sun Jun 12 17:10:30 2022 +0200
53.2 +++ b/libfsserver/lib/directories/directory_provider.cc Wed Aug 10 00:25:44 2022 +0200
53.3 @@ -1,7 +1,7 @@
53.4 /*
53.5 * An object providing access to directory functionality.
53.6 *
53.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
53.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
53.9 *
53.10 * This program is free software; you can redistribute it and/or
53.11 * modify it under the terms of the GNU General Public License as
53.12 @@ -48,10 +48,12 @@
53.13
53.14 /* Return a directory resource initialised with this provider. */
53.15
53.16 -long DirectoryProvider::make_resource(offset_t *size,
53.17 +long DirectoryProvider::make_resource(flags_t flags, offset_t *size,
53.18 object_flags_t *object_flags,
53.19 Resource **resource)
53.20 {
53.21 + (void) flags;
53.22 +
53.23 /* Provide non-file values for certain outputs. */
53.24
53.25 *size = 0;
54.1 --- a/libfsserver/lib/files/file_pager.cc Sun Jun 12 17:10:30 2022 +0200
54.2 +++ b/libfsserver/lib/files/file_pager.cc Wed Aug 10 00:25:44 2022 +0200
54.3 @@ -1,7 +1,7 @@
54.4 /*
54.5 * File-specific pager functionality.
54.6 *
54.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
54.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
54.9 *
54.10 * This program is free software; you can redistribute it and/or
54.11 * modify it under the terms of the GNU General Public License as
54.12 @@ -19,18 +19,22 @@
54.13 * Boston, MA 02110-1301, USA
54.14 */
54.15
54.16 +#include <fsclient/file.h> /* file_region_flags */
54.17 +#include <systypes/fcntl.h>
54.18 +
54.19 +#include "copied_page_mapper.h"
54.20 #include "file_pager.h"
54.21 #include "mapped_file_object_server.h"
54.22
54.23
54.24
54.25 /* Initialise a pager for a file with a unique file identifier, file provider,
54.26 - mapping flags and a file registry. The provider offers a shared page mapper
54.27 + opening flags and a file registry. The provider offers a shared page mapper
54.28 for moderating access to loaded pages. */
54.29
54.30 -FilePager::FilePager(fileid_t fileid, FileProvider *provider, map_flags_t flags)
54.31 -: Pager(provider->mapper(), flags),
54.32 - _provider(provider), fileid(fileid)
54.33 +FilePager::FilePager(fileid_t fileid, FileProvider *provider, flags_t flags)
54.34 +: Pager(provider->mapper(), file_region_flags(flags)),
54.35 + _provider(provider), _flags(flags), fileid(fileid)
54.36 {
54.37 }
54.38
54.39 @@ -50,9 +54,10 @@
54.40
54.41 void FilePager::close()
54.42 {
54.43 - /* Notify other users of the file. */
54.44 + /* Notify other users of the file and unsubscribe. */
54.45
54.46 _provider->notify_others(_endpoint, NOTIFY_PEER_CLOSED);
54.47 + unsubscribe();
54.48
54.49 /* Detach the pager, potentially removing the file provider. */
54.50
54.51 @@ -90,21 +95,43 @@
54.52 return err;
54.53 }
54.54
54.55 -long FilePager::mmap(offset_t position, offset_t length, offset_t *start_pos,
54.56 - offset_t *end_pos, offset_t *size)
54.57 +long FilePager::mmap(offset_t position, offset_t length,
54.58 + offset_t start_visible, offset_t end_visible,
54.59 + offset_t *start_pos, offset_t *end_pos, offset_t *size)
54.60 {
54.61 /* Set the limits of the paged region. */
54.62
54.63 - return Pager::mmap(position, length, start_pos, end_pos, size);
54.64 + long err = Pager::mmap(position, length, start_visible, end_visible, start_pos,
54.65 + end_pos, size);
54.66 +
54.67 + if (err)
54.68 + return err;
54.69 +
54.70 + /* Impose copy-on-write semantics where appropriate. */
54.71 +
54.72 + if ((_mapper != _mapper_copied) && copy_on_write())
54.73 + {
54.74 + _mapper_copied = new CopiedPageMapper(_mapper);
54.75 + _mapper = _mapper_copied;
54.76 + }
54.77 +
54.78 + return L4_EOK;
54.79 +}
54.80 +
54.81 +/* Return whether the pager should employ copy-on-write semantics. */
54.82 +
54.83 +bool FilePager::copy_on_write()
54.84 +{
54.85 + return (_flags == O_RDONLY) && (_map_flags & L4RE_DS_F_W);
54.86 }
54.87
54.88
54.89
54.90 /* Generic pager operations. */
54.91
54.92 -long FilePager::map(offset_t offset, address_t hot_spot, map_flags_t flags, l4_snd_fpage_t *region)
54.93 +long FilePager::map(offset_t offset, address_t hot_spot, map_flags_t map_flags, l4_snd_fpage_t *region)
54.94 {
54.95 - return Pager::map(offset, hot_spot, flags, region);
54.96 + return Pager::map(offset, hot_spot, map_flags, region);
54.97 }
54.98
54.99
55.1 --- a/libfsserver/lib/files/file_provider.cc Sun Jun 12 17:10:30 2022 +0200
55.2 +++ b/libfsserver/lib/files/file_provider.cc Wed Aug 10 00:25:44 2022 +0200
55.3 @@ -1,7 +1,7 @@
55.4 /*
55.5 * An object providing access to file functionality.
55.6 *
55.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
55.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
55.9 *
55.10 * This program is free software; you can redistribute it and/or
55.11 * modify it under the terms of the GNU General Public License as
55.12 @@ -26,9 +26,9 @@
55.13
55.14 /* Initialise the provider with a page 'mapper' for the file's contents. */
55.15
55.16 -FileProvider::FileProvider(fileid_t fileid, map_flags_t flags,
55.17 - ProviderRegistry *registry, PageMapper *mapper)
55.18 -: Provider(fileid, registry), _flags(flags), _mapper(mapper)
55.19 +FileProvider::FileProvider(fileid_t fileid, ProviderRegistry *registry,
55.20 + PageMapper *mapper)
55.21 +: Provider(fileid, registry), _mapper(mapper)
55.22 {
55.23 }
55.24
55.25 @@ -37,11 +37,12 @@
55.26 FileProvider::~FileProvider()
55.27 {
55.28 /* Accessors are allocated exclusively for page mappers for files, and
55.29 - so can be deleted here. In general, the page mapper may not have
55.30 - exclusive ownership of an accessor. */
55.31 + so can be deleted here. */
55.32
55.33 Accessor *accessor = _mapper->accessor();
55.34 delete _mapper;
55.35 +
55.36 + accessor->close();
55.37 delete accessor;
55.38 }
55.39
55.40 @@ -54,13 +55,14 @@
55.41
55.42 /* Return a file pager initialised with a provider, page mapper and accessor. */
55.43
55.44 -long FileProvider::make_resource(offset_t *size, object_flags_t *object_flags,
55.45 +long FileProvider::make_resource(flags_t flags, offset_t *size,
55.46 + object_flags_t *object_flags,
55.47 Resource **resource)
55.48 {
55.49 /* Initialise the pager with the provider and a reference to this object for
55.50 detaching from the provider. */
55.51
55.52 - FilePager *pager = new FilePager(_fileid, this, _flags);
55.53 + FilePager *pager = new FilePager(_fileid, this, flags);
55.54
55.55 /* Obtain the size details from the pager, also providing appropriate
55.56 flags. */
56.1 --- a/libfsserver/lib/generic/pager.cc Sun Jun 12 17:10:30 2022 +0200
56.2 +++ b/libfsserver/lib/generic/pager.cc Wed Aug 10 00:25:44 2022 +0200
56.3 @@ -1,7 +1,7 @@
56.4 /*
56.5 * Generic pager functionality.
56.6 *
56.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
56.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
56.9 *
56.10 * This program is free software; you can redistribute it and/or
56.11 * modify it under the terms of the GNU General Public License as
56.12 @@ -23,13 +23,19 @@
56.13 #include "ipc.h"
56.14 #include "pager.h"
56.15
56.16 +#include "copied_page_mapper.h"
56.17 +#include "masked_page_mapper.h"
56.18 +
56.19
56.20
56.21 /* Initialise the pager with a page mapper and the given flags controlling
56.22 access to a file. */
56.23
56.24 -Pager::Pager(PageMapper *mapper, map_flags_t flags)
56.25 -: _start(0), _size(0), _mapper(mapper), _flags(flags)
56.26 +Pager::Pager(GenericPageMapper *mapper, map_flags_t map_flags)
56.27 +: _start(0), _size(0),
56.28 + _mapper(mapper), _mapper_base(mapper), _mapper_masked(NULL),
56.29 + _mapper_copied(NULL),
56.30 + _map_flags(map_flags)
56.31 {
56.32 }
56.33
56.34 @@ -37,6 +43,17 @@
56.35
56.36 void Pager::close()
56.37 {
56.38 + if (_mapper_masked != NULL)
56.39 + {
56.40 + delete _mapper_masked;
56.41 + _mapper_masked = NULL;
56.42 + }
56.43 +
56.44 + if (_mapper_copied != NULL)
56.45 + {
56.46 + delete _mapper_copied;
56.47 + _mapper_copied = NULL;
56.48 + }
56.49 }
56.50
56.51 /* Flush data to the file. */
56.52 @@ -61,8 +78,9 @@
56.53
56.54 /* Expose a region of the file. */
56.55
56.56 -long Pager::mmap(offset_t position, offset_t length, offset_t *start_pos,
56.57 - offset_t *end_pos, offset_t *size)
56.58 +long Pager::mmap(offset_t position, offset_t length,
56.59 + offset_t start_visible, offset_t end_visible,
56.60 + offset_t *start_pos, offset_t *end_pos, offset_t *size)
56.61 {
56.62 /* Define region characteristics. */
56.63
56.64 @@ -73,7 +91,21 @@
56.65
56.66 *start_pos = _start;
56.67 *end_pos = _start + _size;
56.68 - *size = _mapper->get_data_size();
56.69 + *size = _mapper_base->get_data_size();
56.70 +
56.71 + /* Permit masking of mapped regions. */
56.72 +
56.73 + if ((start_visible || end_visible) &&
56.74 + ((*start_pos != start_visible) || (*end_pos != end_visible)))
56.75 + {
56.76 + /* Introduce the masked page and copied page mappers. */
56.77 +
56.78 + _mapper_masked = new MaskedPageMapper(_mapper_base, start_visible, end_visible);
56.79 + _mapper_copied = new CopiedPageMapper(_mapper_masked);
56.80 + _mapper = _mapper_copied;
56.81 + }
56.82 + else
56.83 + _mapper = _mapper_base;
56.84
56.85 return L4_EOK;
56.86 }
56.87 @@ -81,28 +113,33 @@
56.88 /* Map a flexpage corresponding to the dataspace 'offset' involving a 'hot_spot'
56.89 (flexpage offset). */
56.90
56.91 -long Pager::map(offset_t offset, address_t hot_spot, map_flags_t flags,
56.92 +long Pager::map(offset_t offset, address_t hot_spot, map_flags_t map_flags,
56.93 l4_snd_fpage_t *region)
56.94 {
56.95 offset_t file_offset = _start + offset;
56.96 offset_t max_offset = _start + _size;
56.97
56.98 - /* Prevent access beyond that defined by the pager. */
56.99 + /* Prevent access beyond that defined by the pager.
56.100 + NOTE: Permitting executable requests here. This needs to be configured
56.101 + when opening the pager or by another means. */
56.102
56.103 - if (flags & ~_flags)
56.104 + if (map_flags & (~(_map_flags | L4RE_DS_F_X)))
56.105 return -L4_EACCESS;
56.106
56.107 - Flexpage *flexpage = _mapper->get(file_offset, flags);
56.108 + /* Obtain a flexpage from the page mapper. */
56.109 +
56.110 + Flexpage *flexpage = _mapper->get(file_offset, map_flags);
56.111
56.112 /* Issue the flexpage via the IPC system. */
56.113
56.114 - long err = ipc_prepare_flexpage(flexpage, file_offset, max_offset, hot_spot,
56.115 - flags, region);
56.116 + long err = ipc_prepare_flexpage(flexpage, file_offset, max_offset,
56.117 + hot_spot, map_flags, region);
56.118
56.119 if (!err)
56.120 err = complete_Dataspace_map(*region);
56.121
56.122 - /* After the flexpage is issued, it is queued for future reuse. */
56.123 + /* After the obtained flexpage is issued, it is queued for future reuse, if
56.124 + appropriate for the mapper concerned. */
56.125
56.126 _mapper->queue(flexpage);
56.127
57.1 --- a/libfsserver/lib/generic/resource_registry.cc Sun Jun 12 17:10:30 2022 +0200
57.2 +++ b/libfsserver/lib/generic/resource_registry.cc Wed Aug 10 00:25:44 2022 +0200
57.3 @@ -37,15 +37,6 @@
57.4
57.5
57.6
57.7 -/* Convert opening flags to map-compatible paging flags. */
57.8 -
57.9 -map_flags_t ResourceRegistry::get_flags(flags_t flags)
57.10 -{
57.11 - return flags & (O_WRONLY | O_RDWR) ? L4RE_DS_MAP_FLAG_RW : L4RE_DS_MAP_FLAG_RO;
57.12 -}
57.13 -
57.14 -
57.15 -
57.16 /* Make a directory provider. */
57.17
57.18 long ResourceRegistry::make_directory_provider(FileOpening *opening,
57.19 @@ -81,7 +72,7 @@
57.20 return err;
57.21
57.22 PageMapper *mapper = new PageMapper(accessor, _pages);
57.23 - *provider = new FileProvider(fileid, get_flags(flags), this, mapper);
57.24 + *provider = new FileProvider(fileid, this, mapper);
57.25 return L4_EOK;
57.26 }
57.27
57.28 @@ -167,7 +158,7 @@
57.29
57.30 /* Make a resource for the provider. */
57.31
57.32 - return provider->make_resource(size, object_flags, resource);
57.33 + return provider->make_resource(flags, size, object_flags, resource);
57.34 }
57.35
57.36 /* Request the removal of a filesystem object through any active provider or
58.1 --- a/libfsserver/lib/generic/resource_server.cc Sun Jun 12 17:10:30 2022 +0200
58.2 +++ b/libfsserver/lib/generic/resource_server.cc Wed Aug 10 00:25:44 2022 +0200
58.3 @@ -1,7 +1,7 @@
58.4 /*
58.5 * Resource server functionality.
58.6 *
58.7 - * Copyright (C) 2018, 2019, 2020, 2021 Paul Boddie <paul@boddie.org.uk>
58.8 + * Copyright (C) 2018, 2019, 2020, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
58.9 *
58.10 * This program is free software; you can redistribute it and/or
58.11 * modify it under the terms of the GNU General Public License as
58.12 @@ -68,8 +68,8 @@
58.13 return resource_start_config(_config, _resource);
58.14 }
58.15
58.16 -/* A convenience method starting a thread and providing the server
58.17 - capability. */
58.18 +/* A convenience method starting a thread and returning the server capability
58.19 + employed via the given parameter. */
58.20
58.21 long ResourceServer::start_thread(l4_cap_idx_t *server)
58.22 {
59.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
59.2 +++ b/libfsserver/lib/mapping/copied_page_mapper.cc Wed Aug 10 00:25:44 2022 +0200
59.3 @@ -0,0 +1,163 @@
59.4 +/*
59.5 + * A page mapper providing copied memory pages or deferring to another page
59.6 + * mapper to satisfy file accesses.
59.7 + *
59.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
59.9 + *
59.10 + * This program is free software; you can redistribute it and/or
59.11 + * modify it under the terms of the GNU General Public License as
59.12 + * published by the Free Software Foundation; either version 2 of
59.13 + * the License, or (at your option) any later version.
59.14 + *
59.15 + * This program is distributed in the hope that it will be useful,
59.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
59.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
59.18 + * GNU General Public License for more details.
59.19 + *
59.20 + * You should have received a copy of the GNU General Public License
59.21 + * along with this program; if not, write to the Free Software
59.22 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
59.23 + * Boston, MA 02110-1301, USA
59.24 + */
59.25 +
59.26 +#include <l4/re/c/dataspace.h>
59.27 +
59.28 +#include <string.h>
59.29 +
59.30 +#include "copied_page_mapper.h"
59.31 +
59.32 +
59.33 +
59.34 +/* Provide mapped pages populated with the given 'mapper', with pages obtained
59.35 + from the given 'pages' collection. */
59.36 +
59.37 +CopiedPageMapper::CopiedPageMapper(GenericPageMapper *mapper)
59.38 +: _mapper(mapper)
59.39 +{
59.40 + _size = _mapper->get_data_size();
59.41 +}
59.42 +
59.43 +/* Upon deallocation, release allocated flexpages. */
59.44 +
59.45 +CopiedPageMapper::~CopiedPageMapper()
59.46 +{
59.47 + while (!_queue.empty())
59.48 + {
59.49 + Flexpage *flexpage = _queue.front();
59.50 +
59.51 + _queue.pop_front();
59.52 + _memory.release(flexpage->region);
59.53 + delete flexpage;
59.54 + }
59.55 +}
59.56 +
59.57 +/* Interface for the pager. */
59.58 +
59.59 +/* Return a flexpage providing access to the indicated file 'offset'.
59.60 +
59.61 + The returned flexpage will either provide direct access to the underlying
59.62 + file content or be a completely new flexpage modified through writes to
59.63 + memory. */
59.64 +
59.65 +Flexpage *CopiedPageMapper::get(offset_t offset, map_flags_t flags)
59.66 +{
59.67 + Flexpage *f = find(offset);
59.68 +
59.69 + /* Defer to the underlying page mapper if no flexpage was found. */
59.70 +
59.71 + if (f == NULL)
59.72 + {
59.73 + f = _mapper->get(offset, flags);
59.74 +
59.75 + /* Replicate the underlying flexpage if writing. */
59.76 +
59.77 + if (flags & L4RE_DS_F_W)
59.78 + {
59.79 + Flexpage *rf = replicate_flexpage(offset, f);
59.80 + _mapper->queue(f);
59.81 + f = rf;
59.82 + }
59.83 + }
59.84 +
59.85 + /* Upgrade the access flags. */
59.86 +
59.87 + f->upgrade(flags);
59.88 + return f;
59.89 +}
59.90 +
59.91 +/* Queue the given 'flexpage'. */
59.92 +
59.93 +void CopiedPageMapper::queue(Flexpage *flexpage)
59.94 +{
59.95 + if (dynamic_cast<CopiedFlexpage *>(flexpage) == NULL)
59.96 + _mapper->queue(flexpage);
59.97 +}
59.98 +
59.99 +/* Flush pages in the given range from 'start' with 'size'. */
59.100 +
59.101 +void CopiedPageMapper::flush_all(offset_t start, offset_t size)
59.102 +{
59.103 + /* NOTE: This might be superfluous since copy-on-write regions should not
59.104 + update content. */
59.105 +
59.106 + _mapper->flush_all(start, size);
59.107 +}
59.108 +
59.109 +/* Return the maximum extent of the mapped resource. */
59.110 +
59.111 +offset_t CopiedPageMapper::get_data_size()
59.112 +{
59.113 + return _size;
59.114 +}
59.115 +
59.116 +/* Set the maximum extent of the mapped resource. */
59.117 +
59.118 +void CopiedPageMapper::set_data_size(offset_t size)
59.119 +{
59.120 + _size = size;
59.121 +}
59.122 +
59.123 +/* Internal flexpage retrieval methods. */
59.124 +
59.125 +/* Find an existing flexpage for 'offset'. */
59.126 +
59.127 +Flexpage *CopiedPageMapper::find(offset_t offset)
59.128 +{
59.129 + return _map.find(offset);
59.130 +}
59.131 +
59.132 +/* Replicate an underlying flexpage for the file 'offset' using the given
59.133 + 'flexpage'. */
59.134 +
59.135 +Flexpage *CopiedPageMapper::replicate_flexpage(offset_t offset, Flexpage *flexpage)
59.136 +{
59.137 + /* Obtain a new memory region and a new flexpage. */
59.138 +
59.139 + Region *region = _memory.region(flexpage->size);
59.140 + Flexpage *replicated = new CopiedFlexpage(region);
59.141 +
59.142 + /* Configure the flexpage for the file region. */
59.143 +
59.144 + replicated->reset(offset);
59.145 +
59.146 + /* Copy the contents of the underlying flexpage. */
59.147 +
59.148 + memcpy((void *) region->start, (const void *) flexpage->region->start, flexpage->size);
59.149 +
59.150 + /* Register the flexpage for future accesses and for deallocation. */
59.151 +
59.152 + _map.insert(replicated);
59.153 + _queue.push_back(replicated);
59.154 + return replicated;
59.155 +}
59.156 +
59.157 +
59.158 +
59.159 +/* Copied flexpage constructor. */
59.160 +
59.161 +CopiedFlexpage::CopiedFlexpage(Region *region)
59.162 +: Flexpage(region)
59.163 +{
59.164 +}
59.165 +
59.166 +// vim: tabstop=4 expandtab shiftwidth=4
60.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
60.2 +++ b/libfsserver/lib/mapping/generic_page_mapper.cc Wed Aug 10 00:25:44 2022 +0200
60.3 @@ -0,0 +1,30 @@
60.4 +/*
60.5 + * A generic page mapper providing memory pages to satisfy file accesses.
60.6 + *
60.7 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
60.8 + *
60.9 + * This program is free software; you can redistribute it and/or
60.10 + * modify it under the terms of the GNU General Public License as
60.11 + * published by the Free Software Foundation; either version 2 of
60.12 + * the License, or (at your option) any later version.
60.13 + *
60.14 + * This program is distributed in the hope that it will be useful,
60.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
60.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
60.17 + * GNU General Public License for more details.
60.18 + *
60.19 + * You should have received a copy of the GNU General Public License
60.20 + * along with this program; if not, write to the Free Software
60.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
60.22 + * Boston, MA 02110-1301, USA
60.23 + */
60.24 +
60.25 +#include "generic_page_mapper.h"
60.26 +
60.27 +
60.28 +
60.29 +GenericPageMapper::~GenericPageMapper()
60.30 +{
60.31 +}
60.32 +
60.33 +// vim: tabstop=4 expandtab shiftwidth=4
61.1 --- a/libfsserver/lib/mapping/ipc.cc Sun Jun 12 17:10:30 2022 +0200
61.2 +++ b/libfsserver/lib/mapping/ipc.cc Wed Aug 10 00:25:44 2022 +0200
61.3 @@ -1,7 +1,7 @@
61.4 /*
61.5 * Interprocess communication utilities.
61.6 *
61.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
61.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
61.9 *
61.10 * This program is free software; you can redistribute it and/or
61.11 * modify it under the terms of the GNU General Public License as
61.12 @@ -28,12 +28,17 @@
61.13 #include "ipc.h"
61.14
61.15
61.16 +
61.17 /* Make an L4 representation of the given flexpage. */
61.18
61.19 static l4_fpage_t ipc_get_fpage(SendFlexpage *send_flexpage)
61.20 {
61.21 - return l4_fpage(send_flexpage->base_addr, send_flexpage->order,
61.22 - (send_flexpage->flags & L4RE_DS_MAP_FLAG_RW) ? L4_FPAGE_RW : L4_FPAGE_RO);
61.23 + unsigned char flags = send_flexpage->flags;
61.24 +
61.25 + if (!flags)
61.26 + flags = L4RE_DS_MAP_FLAG_RO;
61.27 +
61.28 + return l4_fpage(send_flexpage->base_addr, send_flexpage->order, flags);
61.29 }
61.30
61.31 /* Make a representation of a flexpage for the IPC system. */
62.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
62.2 +++ b/libfsserver/lib/mapping/masked_page_mapper.cc Wed Aug 10 00:25:44 2022 +0200
62.3 @@ -0,0 +1,195 @@
62.4 +/*
62.5 + * A page mapper providing memory pages to satisfy file accesses, masking the
62.6 + * limits of a visible region of the file's contents.
62.7 + *
62.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
62.9 + *
62.10 + * This program is free software; you can redistribute it and/or
62.11 + * modify it under the terms of the GNU General Public License as
62.12 + * published by the Free Software Foundation; either version 2 of
62.13 + * the License, or (at your option) any later version.
62.14 + *
62.15 + * This program is distributed in the hope that it will be useful,
62.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
62.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
62.18 + * GNU General Public License for more details.
62.19 + *
62.20 + * You should have received a copy of the GNU General Public License
62.21 + * along with this program; if not, write to the Free Software
62.22 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
62.23 + * Boston, MA 02110-1301, USA
62.24 + */
62.25 +
62.26 +#include <string.h>
62.27 +
62.28 +#include "masked_page_mapper.h"
62.29 +
62.30 +
62.31 +
62.32 +/* Provide mapped pages populated using the given 'mapper', with a visible
62.33 + region defined that causes the limits of this region to be masked. */
62.34 +
62.35 +MaskedPageMapper::MaskedPageMapper(GenericPageMapper *mapper,
62.36 + offset_t start_visible, offset_t end_visible)
62.37 +: _mapper(mapper), _start_visible(start_visible), _end_visible(end_visible)
62.38 +{
62.39 + _size = _mapper->get_data_size();
62.40 +}
62.41 +
62.42 +MaskedPageMapper::~MaskedPageMapper()
62.43 +{
62.44 + if (_start_flexpage.region != NULL)
62.45 + _memory.release(_start_flexpage.region);
62.46 +
62.47 + if (_end_flexpage.region != NULL)
62.48 + _memory.release(_end_flexpage.region);
62.49 +
62.50 + if (_zero_flexpage.region != NULL)
62.51 + _memory.release(_zero_flexpage.region);
62.52 +}
62.53 +
62.54 +/* Interface for the pager. */
62.55 +
62.56 +/* Return a flexpage providing access to the indicated file 'offset'.
62.57 +
62.58 + The returned flexpage will either provide direct access to the underlying
62.59 + file content or be a completely new flexpage containing masked content. */
62.60 +
62.61 +Flexpage *MaskedPageMapper::get(offset_t offset, map_flags_t flags)
62.62 +{
62.63 + Flexpage *f = _mapper->get(offset, flags);
62.64 + Flexpage *mf = get_masked_flexpage(f);
62.65 +
62.66 + if (f != mf)
62.67 + _mapper->queue(f);
62.68 +
62.69 + return mf;
62.70 +}
62.71 +
62.72 +/* Queue the given 'flexpage'. */
62.73 +
62.74 +void MaskedPageMapper::queue(Flexpage *flexpage)
62.75 +{
62.76 + if (dynamic_cast<MaskedFlexpage *>(flexpage) == NULL)
62.77 + _mapper->queue(flexpage);
62.78 +}
62.79 +
62.80 +/* Flush pages in the given range from 'start' with 'size'. */
62.81 +
62.82 +void MaskedPageMapper::flush_all(offset_t start, offset_t size)
62.83 +{
62.84 + /* NOTE: This might be superfluous since masked regions probably should be
62.85 + read-only or copy-on-write. */
62.86 +
62.87 + _mapper->flush_all(start, size);
62.88 +}
62.89 +
62.90 +/* Return the maximum extent of the mapped resource. */
62.91 +
62.92 +offset_t MaskedPageMapper::get_data_size()
62.93 +{
62.94 + return _size;
62.95 +}
62.96 +
62.97 +/* Set the maximum extent of the mapped resource. */
62.98 +
62.99 +void MaskedPageMapper::set_data_size(offset_t size)
62.100 +{
62.101 + _size = size;
62.102 +}
62.103 +
62.104 +/* Internal flexpage retrieval methods. */
62.105 +
62.106 +/* Detect flexpages with masked content, introducing separate flexpages
62.107 + offering masked content from the same region. */
62.108 +
62.109 +Flexpage *MaskedPageMapper::get_masked_flexpage(Flexpage *flexpage)
62.110 +{
62.111 + /* Determine whether the flexpage involves the limits of the visible
62.112 + region or is beyond such limits. */
62.113 +
62.114 + bool has_start = flexpage->supports_position(_start_visible) &&
62.115 + flexpage->base_offset != _start_visible;
62.116 + bool has_end = flexpage->supports_position(_end_visible);
62.117 + bool has_zero = (flexpage->base_offset >= _end_visible) ||
62.118 + (flexpage->base_offset + flexpage->size < _start_visible);
62.119 +
62.120 + /* Return the original flexpage within the visible limits. */
62.121 +
62.122 + if (!has_start && !has_end && !has_zero)
62.123 + return flexpage;
62.124 +
62.125 + /* Allocate and populate a region in one of the preallocated flexpages for
62.126 + masked content. */
62.127 +
62.128 + Flexpage &masked = has_start ? _start_flexpage :
62.129 + has_end ? _end_flexpage :
62.130 + _zero_flexpage;
62.131 +
62.132 + allocate_region(flexpage, masked);
62.133 + populate_region(flexpage, masked, has_start, has_end);
62.134 +
62.135 + /* Associate the preallocated flexpage with the original flexpage. */
62.136 +
62.137 + flexpage->associate(&masked);
62.138 +
62.139 + return &masked;
62.140 +}
62.141 +
62.142 +void MaskedPageMapper::allocate_region(Flexpage *flexpage, Flexpage &masked)
62.143 +{
62.144 + offset_t needed = flexpage->region->size();
62.145 +
62.146 + /* Attempt to re-use an existing region. */
62.147 +
62.148 + if (masked.region != NULL)
62.149 + {
62.150 + if (masked.region->size() == needed)
62.151 + return;
62.152 + else
62.153 + _memory.release(masked.region);
62.154 + }
62.155 +
62.156 + /* Set the region in the flexpage. */
62.157 +
62.158 + masked.set_region(_memory.region(needed));
62.159 + masked.reset(flexpage->base_offset);
62.160 +}
62.161 +
62.162 +void MaskedPageMapper::populate_region(Flexpage *flexpage, Flexpage &masked,
62.163 + bool has_start, bool has_end)
62.164 +{
62.165 + /* Without any limits involved, provide a zero flexpage. */
62.166 +
62.167 + if (!has_start && !has_end)
62.168 + {
62.169 + memset((void *) masked.region->start, 0, masked.size);
62.170 + return;
62.171 + }
62.172 +
62.173 + /* Determine the content limits given start and/or end offsets. */
62.174 +
62.175 + offset_t start_offset = has_start ? _start_visible - masked.base_offset : 0;
62.176 + offset_t end_offset = has_end ? _end_visible - masked.base_offset : masked.size;
62.177 +
62.178 + if (has_start)
62.179 + memset((void *) masked.region->start, 0, start_offset);
62.180 +
62.181 + memcpy((void *) (masked.region->start + start_offset),
62.182 + (const void *) (flexpage->region->start + start_offset),
62.183 + end_offset - start_offset);
62.184 +
62.185 + if (has_end)
62.186 + memset((void *) (masked.region->start + end_offset), 0, masked.size - end_offset);
62.187 +}
62.188 +
62.189 +
62.190 +
62.191 +/* Masked flexpage constructor. */
62.192 +
62.193 +MaskedFlexpage::MaskedFlexpage(Region *region)
62.194 +: Flexpage(region)
62.195 +{
62.196 +}
62.197 +
62.198 +// vim: tabstop=4 expandtab shiftwidth=4
63.1 --- a/libfsserver/lib/mapping/page_mapper.cc Sun Jun 12 17:10:30 2022 +0200
63.2 +++ b/libfsserver/lib/mapping/page_mapper.cc Wed Aug 10 00:25:44 2022 +0200
63.3 @@ -1,7 +1,7 @@
63.4 /*
63.5 * A page mapper providing memory pages to satisfy file accesses.
63.6 *
63.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
63.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
63.9 *
63.10 * This program is free software; you can redistribute it and/or
63.11 * modify it under the terms of the GNU General Public License as
63.12 @@ -130,11 +130,6 @@
63.13 {
63.14 Flexpage *flexpage = _pages->flexpage();
63.15
63.16 - /* Obtain an existing flexpage and reuse it. */
63.17 -
63.18 - if (flexpage == NULL)
63.19 - flexpage = _pages->remove();
63.20 -
63.21 flexpage->reset(offset);
63.22
63.23 fill(flexpage);
63.24 @@ -162,11 +157,31 @@
63.25 {
63.26 if (flexpage->decrement() || purge)
63.27 {
63.28 + /* NOTE: Derived flexpages might potentially support their contents
63.29 + being merged into the flushed data, although this is a
63.30 + non-trivial problem. */
63.31 +
63.32 if (flexpage->modified())
63.33 _accessor->flush(flexpage);
63.34
63.35 + /* Unmap the flexpage, requiring users of its memory to request another
63.36 + flexpage in future. */
63.37 +
63.38 ipc_unmap_flexpage(flexpage);
63.39 flexpage->invalidate();
63.40 +
63.41 + /* Unmap all derived flexpages, since these rely on the underlying file
63.42 + contents. */
63.43 +
63.44 + DerivedFlexpages::iterator it;
63.45 +
63.46 + for (it = flexpage->derived.begin(); it != flexpage->derived.end(); it++)
63.47 + {
63.48 + ipc_unmap_flexpage(*it);
63.49 + (*it)->invalidate();
63.50 + }
63.51 +
63.52 + flexpage->disassociate();
63.53 }
63.54 }
63.55
64.1 --- a/libfsserver/lib/pages/pages.cc Sun Jun 12 17:10:30 2022 +0200
64.2 +++ b/libfsserver/lib/pages/pages.cc Wed Aug 10 00:25:44 2022 +0200
64.3 @@ -1,7 +1,7 @@
64.4 /*
64.5 * A page collection abstraction providing pages from a queue to users.
64.6 *
64.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
64.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
64.9 *
64.10 * This program is free software; you can redistribute it and/or
64.11 * modify it under the terms of the GNU General Public License as
64.12 @@ -19,8 +19,6 @@
64.13 * Boston, MA 02110-1301, USA
64.14 */
64.15
64.16 -#include <mem/memory_incremental.h>
64.17 -
64.18 #include "pages.h"
64.19
64.20
64.21 @@ -68,7 +66,7 @@
64.22 if (region != NULL)
64.23 return new Flexpage(region);
64.24 else
64.25 - return NULL;
64.26 + return remove();
64.27 }
64.28
64.29 /* Queue an entry associating the given 'owner' and 'flexpage'. */
65.1 --- a/libfsserver/lib/pipes/pipe_pager.cc Sun Jun 12 17:10:30 2022 +0200
65.2 +++ b/libfsserver/lib/pipes/pipe_pager.cc Wed Aug 10 00:25:44 2022 +0200
65.3 @@ -1,7 +1,7 @@
65.4 /*
65.5 * A pipe pager providing access to pipe content and navigation support.
65.6 *
65.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
65.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
65.9 *
65.10 * This program is free software; you can redistribute it and/or
65.11 * modify it under the terms of the GNU General Public License as
65.12 @@ -65,9 +65,10 @@
65.13
65.14 unsigned int attached = _paging->detach();
65.15
65.16 - /* Notify the other endpoint. */
65.17 + /* Notify the other endpoint and unsubscribe. */
65.18
65.19 _paging->notify_others(_writing ? PipePaging::WRITER : PipePaging::READER, NOTIFY_PEER_CLOSED);
65.20 + unsubscribe();
65.21
65.22 /* Deallocate the paging coordinator if no other endpoints are active. */
65.23
66.1 --- a/libipc/include/ipc/map.h Sun Jun 12 17:10:30 2022 +0200
66.2 +++ b/libipc/include/ipc/map.h Wed Aug 10 00:25:44 2022 +0200
66.3 @@ -27,13 +27,18 @@
66.4
66.5 struct ipc_mapped_cap
66.6 {
66.7 - l4_umword_t index;
66.8 + l4_cap_idx_t mapped_cap;
66.9 l4_cap_idx_t cap;
66.10 unsigned char rights;
66.11 + l4_umword_t obj_rights;
66.12 };
66.13
66.14 long ipc_map_capability(l4_cap_idx_t task, struct ipc_mapped_cap mapped_cap);
66.15
66.16 -long ipc_map_capabilities(l4_cap_idx_t task, struct ipc_mapped_cap mapped_caps[]);
66.17 +long ipc_map_capabilities(l4_cap_idx_t task, struct ipc_mapped_cap mapped_caps[],
66.18 + unsigned int *count);
66.19
66.20 EXTERN_C_END
66.21 +
66.22 +/* vim: tabstop=2 expandtab shiftwidth=2
66.23 +*/
67.1 --- a/libipc/include/ipc/mem_ipc.h Sun Jun 12 17:10:30 2022 +0200
67.2 +++ b/libipc/include/ipc/mem_ipc.h Wed Aug 10 00:25:44 2022 +0200
67.3 @@ -32,7 +32,8 @@
67.4 long ipc_allocate_align(unsigned long size, l4re_rm_flags_t flags,
67.5 unsigned char align, void **addr, l4re_ds_t *ds);
67.6
67.7 -long ipc_new_dataspace(l4_cap_idx_t cap, l4_mword_t size, l4_umword_t flags, l4_umword_t align);
67.8 +long ipc_new_dataspace(l4_mword_t size, l4_umword_t flags, l4_umword_t align,
67.9 + l4re_ds_t *ds);
67.10
67.11 long ipc_attach_dataspace(l4re_ds_t ds, unsigned long size, void **addr);
67.12
67.13 @@ -45,3 +46,6 @@
67.14 long ipc_dataspace_size(l4_cap_idx_t cap, unsigned long *size);
67.15
67.16 EXTERN_C_END
67.17 +
67.18 +/* vim: tabstop=2 expandtab shiftwidth=2
67.19 +*/
68.1 --- a/libipc/include/ipc/message.h Sun Jun 12 17:10:30 2022 +0200
68.2 +++ b/libipc/include/ipc/message.h Wed Aug 10 00:25:44 2022 +0200
68.3 @@ -1,7 +1,7 @@
68.4 /*
68.5 * Interprocess communication message abstraction.
68.6 *
68.7 - * Copyright (C) 2018, 2019, 2021 Paul Boddie <paul@boddie.org.uk>
68.8 + * Copyright (C) 2018, 2019, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
68.9 *
68.10 * This program is free software; you can redistribute it and/or
68.11 * modify it under the terms of the GNU General Public License as
68.12 @@ -46,6 +46,10 @@
68.13 l4_msgtag_t tag;
68.14 unsigned int expected_items;
68.15
68.16 + /* Receive item counter. */
68.17 +
68.18 + unsigned int receive_items;
68.19 +
68.20 /* Output details. */
68.21
68.22 unsigned int words;
68.23 @@ -109,6 +113,7 @@
68.24 void ipc_message_add_item(ipc_message_t *msg, l4_cap_idx_t cap);
68.25 void ipc_message_add_fpage(ipc_message_t *msg, l4_snd_fpage_t fpage);
68.26 void ipc_message_add_page(ipc_message_t *msg, l4_umword_t hot_spot, l4_fpage_t fpage);
68.27 +void ipc_message_add_receive_fpage(ipc_message_t *msg, l4_snd_fpage_t fpage);
68.28 void ipc_message_add_string(ipc_message_t *msg, const char *value);
68.29 void ipc_message_add_word(ipc_message_t *msg, l4_umword_t value);
68.30 void ipc_message_propagate_item(ipc_message_t *msg, l4_cap_idx_t cap);
68.31 @@ -136,6 +141,7 @@
68.32 long ipc_message_import_dataspace(ipc_message_t *msg, int item, l4re_ds_t *mem, l4_addr_t *addr);
68.33 long ipc_message_import_fpage(ipc_message_t *msg, int item, l4_snd_fpage_t *fpage);
68.34 void ipc_message_propagate_capability(ipc_message_t *msg, int item, l4_cap_idx_t ref);
68.35 +void ipc_message_receive_fpage(ipc_message_t *msg, int item, l4_snd_fpage_t fpage);
68.36 l4_msgtag_t ipc_message_reply_tag(ipc_message_t *msg);
68.37 l4_msgtag_t ipc_message_request_tag(ipc_message_t *msg, int op);
68.38
69.1 --- a/libipc/include/ipc/server.h Sun Jun 12 17:10:30 2022 +0200
69.2 +++ b/libipc/include/ipc/server.h Wed Aug 10 00:25:44 2022 +0200
69.3 @@ -34,6 +34,12 @@
69.4 (ipc_server_handler_type) handle_##TYPE, \
69.5 NAME)
69.6
69.7 +/* A convenience macro for initialising a server. */
69.8 +
69.9 +#define ipc_server_init_for(CONFIG, TYPE, POINTER) \
69.10 + _ipc_server_init_for(CONFIG, TYPE##_expected_items, (TYPE *) POINTER, \
69.11 + (ipc_server_handler_type) handle_##TYPE)
69.12 +
69.13 /* A convenience macro for adding a configuration to an existing server. */
69.14
69.15 #define ipc_server_add_config(CONFIG, TYPE, POINTER, THREAD) \
69.16 @@ -124,6 +130,11 @@
69.17 long _ipc_server_loop_for(int expected_items, void *handler_obj,
69.18 ipc_server_handler_type handler, const char *name);
69.19
69.20 +/* Initialise a server. */
69.21 +
69.22 +long _ipc_server_init_for(ipc_server_config_type *config, int expected_items,
69.23 + void *handler_obj, ipc_server_handler_type handler);
69.24 +
69.25 /* Add handling of incoming messages to an existing server. */
69.26
69.27 long _ipc_server_add_config(ipc_server_config_type *config, int expected_items,
69.28 @@ -160,6 +171,11 @@
69.29
69.30 long ipc_server_start_config(ipc_server_config_type *config);
69.31
69.32 +/* Initialise and start a server using the given configuration and thread. */
69.33 +
69.34 +long ipc_server_start_config_thread(ipc_server_config_type *config,
69.35 + l4_cap_idx_t thread);
69.36 +
69.37 EXTERN_C_END
69.38
69.39 /* vim: tabstop=2 expandtab shiftwidth=2
70.1 --- a/libipc/lib/src/map.c Sun Jun 12 17:10:30 2022 +0200
70.2 +++ b/libipc/lib/src/map.c Wed Aug 10 00:25:44 2022 +0200
70.3 @@ -34,18 +34,24 @@
70.4 {
70.5 return l4_error(l4_task_map(task, L4RE_THIS_TASK_CAP,
70.6 l4_obj_fpage(mapped_cap.cap, 0, mapped_cap.rights),
70.7 - l4_map_obj_control(mapped_cap.index, L4_MAP_ITEM_MAP)));
70.8 + l4_map_obj_control(mapped_cap.mapped_cap, L4_MAP_ITEM_MAP) |
70.9 + mapped_cap.obj_rights));
70.10 }
70.11
70.12 /* Map several capabilities to another task. */
70.13
70.14 -long ipc_map_capabilities(l4_cap_idx_t task, struct ipc_mapped_cap mapped_caps[])
70.15 +long ipc_map_capabilities(l4_cap_idx_t task, struct ipc_mapped_cap mapped_caps[],
70.16 + unsigned int *count)
70.17 {
70.18 long err = L4_EOK;
70.19 + unsigned int i;
70.20
70.21 - for (int i = 0; l4_is_valid_cap(mapped_caps[i].cap) && !err; i++)
70.22 + for (i = 0; l4_is_valid_cap(mapped_caps[i].cap) && !err; i++)
70.23 err = ipc_map_capability(task, mapped_caps[i]);
70.24
70.25 + if (count != NULL)
70.26 + *count = i;
70.27 +
70.28 return err;
70.29 }
70.30
71.1 --- a/libipc/lib/src/mem_ipc.c Sun Jun 12 17:10:30 2022 +0200
71.2 +++ b/libipc/lib/src/mem_ipc.c Wed Aug 10 00:25:44 2022 +0200
71.3 @@ -46,16 +46,9 @@
71.4 long ipc_allocate_align(unsigned long size, l4re_rm_flags_t flags,
71.5 unsigned char align, void **addr, l4re_ds_t *ds)
71.6 {
71.7 - /* Allocate a capability for the dataspace. */
71.8 -
71.9 - *ds = ipc_cap_alloc();
71.10 -
71.11 - if (l4_is_invalid_cap(*ds))
71.12 - return -L4_ENOENT;
71.13 -
71.14 /* Allocate and attach the memory for the dataspace. */
71.15
71.16 - if (ipc_new_dataspace(*ds, size, 0, align))
71.17 + if (ipc_new_dataspace(size, 0, align, ds))
71.18 {
71.19 ipc_cap_free_um(*ds);
71.20 return -L4_ENOMEM;
71.21 @@ -72,9 +65,17 @@
71.22
71.23 /* Create a dataspace. Equivalent to l4re_ma_alloc_align. */
71.24
71.25 -long ipc_new_dataspace(l4_cap_idx_t cap, l4_mword_t size, l4_umword_t flags, l4_umword_t align)
71.26 +long ipc_new_dataspace(l4_mword_t size, l4_umword_t flags, l4_umword_t align,
71.27 + l4re_ds_t *ds)
71.28 {
71.29 - return l4re_ma_alloc_align(size, cap, flags, align);
71.30 + /* Allocate a capability for the dataspace. */
71.31 +
71.32 + *ds = ipc_cap_alloc();
71.33 +
71.34 + if (l4_is_invalid_cap(*ds))
71.35 + return -L4_ENOENT;
71.36 +
71.37 + return l4re_ma_alloc_align(size, *ds, flags, align);
71.38 }
71.39
71.40 /* Attach a dataspace region. Similar to l4re_rm_attach. */
72.1 --- a/libipc/lib/src/message.c Sun Jun 12 17:10:30 2022 +0200
72.2 +++ b/libipc/lib/src/message.c Wed Aug 10 00:25:44 2022 +0200
72.3 @@ -1,7 +1,7 @@
72.4 /*
72.5 * Interprocess communication message abstraction.
72.6 *
72.7 - * Copyright (C) 2018, 2019, 2021 Paul Boddie <paul@boddie.org.uk>
72.8 + * Copyright (C) 2018, 2019, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
72.9 *
72.10 * This program is free software; you can redistribute it and/or
72.11 * modify it under the terms of the GNU General Public License as
72.12 @@ -54,16 +54,7 @@
72.13
72.14 long ipc_message_expect(ipc_message_t *msg, unsigned int expected_items)
72.15 {
72.16 - long err = ipc_message_expect_capabilities(msg, expected_items);
72.17 -
72.18 - if (err)
72.19 - return err;
72.20 -
72.21 - /* Restore the buffer registers immediately. */
72.22 -
72.23 - ipc_message_restore_buffer_registers(msg);
72.24 -
72.25 - return L4_EOK;
72.26 + return ipc_message_expect_capabilities(msg, expected_items);
72.27 }
72.28
72.29 /* Free capabilities expected in messages. */
72.30 @@ -80,6 +71,7 @@
72.31 /* Set a default for expected items. */
72.32
72.33 msg->expected_items = 0;
72.34 + msg->receive_items = 0;
72.35 ipc_message_reset(msg);
72.36 }
72.37
72.38 @@ -106,8 +98,13 @@
72.39
72.40 msg->bregs.bdr = bregs->bdr;
72.41
72.42 - for (i = 0; i < msg->expected_items; i++)
72.43 - msg->bregs.br[i] = bregs->br[i];
72.44 + /* NOTE: Support a mixture of expected items and received flexpages. */
72.45 +
72.46 + if ((msg->expected_items) || (msg->receive_items))
72.47 + {
72.48 + for (i = 0; (i < msg->expected_items) || (i < msg->receive_items * 2); i++)
72.49 + msg->bregs.br[i] = bregs->br[i];
72.50 + }
72.51 }
72.52
72.53 /* Preserve the message registers. */
72.54 @@ -151,8 +148,13 @@
72.55
72.56 bregs->bdr = msg->bregs.bdr;
72.57
72.58 - for (i = 0; i < msg->expected_items; i++)
72.59 - bregs->br[i] = msg->bregs.br[i];
72.60 + /* NOTE: Support a mixture of expected items and received flexpages. */
72.61 +
72.62 + if ((msg->expected_items) || (msg->receive_items))
72.63 + {
72.64 + for (i = 0; (i < msg->expected_items) || (i < msg->receive_items * 2); i++)
72.65 + bregs->br[i] = msg->bregs.br[i];
72.66 + }
72.67 }
72.68
72.69 /* Restore message registers to communicate recorded data and items. */
72.70 @@ -223,6 +225,7 @@
72.71
72.72 void ipc_message_wait(ipc_message_t *msg, l4_umword_t *label)
72.73 {
72.74 + ipc_message_restore_buffer_registers(msg);
72.75 msg->tag = l4_ipc_wait(l4_utcb(), label, L4_IPC_NEVER);
72.76 }
72.77
72.78 @@ -233,6 +236,9 @@
72.79 void ipc_message_add_capability(ipc_message_t *msg, l4_cap_idx_t cap)
72.80 {
72.81 ipc_message_export_capability(msg, msg->items++, cap);
72.82 +
72.83 + /* NOTE: Might use the "grant" operation instead of explicitly discarding. */
72.84 +
72.85 if (cap & IPC_DISCARD_CAP_FLAG)
72.86 ipc_message_discard_capability(msg, cap & ~IPC_DISCARD_CAP_FLAG);
72.87 }
72.88 @@ -242,6 +248,9 @@
72.89 void ipc_message_add_item(ipc_message_t *msg, l4_cap_idx_t cap)
72.90 {
72.91 ipc_message_export_capability(msg, msg->items++, cap);
72.92 +
72.93 + /* NOTE: Might use the "grant" operation instead of explicitly discarding. */
72.94 +
72.95 if (cap & IPC_DISCARD_CAP_FLAG)
72.96 ipc_message_discard_capability(msg, cap & ~IPC_DISCARD_CAP_FLAG);
72.97 }
72.98 @@ -251,7 +260,18 @@
72.99
72.100 void ipc_message_add_fpage(ipc_message_t *msg, l4_snd_fpage_t fpage)
72.101 {
72.102 - ipc_message_export_fpage(msg, msg->items++, fpage);
72.103 + /* Test for {0, l4_fpage_invalid()} as the flexpage to avoid setting an
72.104 + optional flexpage result, useful for the page fault handler. */
72.105 +
72.106 + if (fpage.snd_base || fpage.fpage.raw)
72.107 + ipc_message_export_fpage(msg, msg->items++, fpage);
72.108 +}
72.109 +
72.110 +/* Add a receive window flexpage item to the message. */
72.111 +
72.112 +void ipc_message_add_receive_fpage(ipc_message_t *msg, l4_snd_fpage_t fpage)
72.113 +{
72.114 + ipc_message_receive_fpage(msg, msg->receive_items++, fpage);
72.115 }
72.116
72.117 /* Add a flexpage to the message. */
72.118 @@ -441,6 +461,16 @@
72.119 msg->mregs.mr[msg->words + item * 2 + 1] = fpage.raw;
72.120 }
72.121
72.122 +/* Specify a receive window flexpage item in the message. */
72.123 +
72.124 +void ipc_message_receive_fpage(ipc_message_t *msg, int item, l4_snd_fpage_t fpage)
72.125 +{
72.126 + msg->bregs.br[item * 2] = l4_map_control(fpage.snd_base, 0, 0);
72.127 + msg->bregs.br[item * 2 + 1] = fpage.fpage.raw;
72.128 +}
72.129 +
72.130 +
72.131 +
72.132 /* Import from the message the capability at the given item position, updating
72.133 the buffer registers for future capabilities. */
72.134
72.135 @@ -483,3 +513,6 @@
72.136 ipc_message_export_capability(msg, item, ref);
72.137 ipc_message_discard_capability(msg, ref);
72.138 }
72.139 +
72.140 +/* vim: tabstop=2 expandtab shiftwidth=2
72.141 +*/
73.1 --- a/libipc/lib/src/server.c Sun Jun 12 17:10:30 2022 +0200
73.2 +++ b/libipc/lib/src/server.c Wed Aug 10 00:25:44 2022 +0200
73.3 @@ -166,24 +166,38 @@
73.4 return err;
73.5 }
73.6
73.7 - ipc_server_init_config(&config);
73.8 - config.expected_items = expected_items;
73.9 - config.handler = handler;
73.10 - config.handler_obj = handler_obj;
73.11 + _ipc_server_init_for(&config, expected_items, handler_obj, handler);
73.12
73.13 return ipc_server_start_config(&config);
73.14 }
73.15
73.16 +/* Initialise a server for a given object. */
73.17 +
73.18 +long _ipc_server_init_for(ipc_server_config_type *config, int expected_items,
73.19 + void *handler_obj, ipc_server_handler_type handler)
73.20 +{
73.21 + ipc_server_init_config(config);
73.22 +
73.23 + config->expected_items = expected_items;
73.24 + config->handler = handler;
73.25 + config->handler_obj = handler_obj;
73.26 +}
73.27 +
73.28 /* Associate a new configuration with an existing server endpoint. */
73.29
73.30 long _ipc_server_add_config(ipc_server_config_type *config, int expected_items,
73.31 void *handler_obj, ipc_server_handler_type handler,
73.32 l4_cap_idx_t thread)
73.33 {
73.34 - ipc_server_init_config(config);
73.35 - config->expected_items = expected_items;
73.36 - config->handler = handler;
73.37 - config->handler_obj = handler_obj;
73.38 + _ipc_server_init_for(config, expected_items, handler_obj, handler);
73.39 + return ipc_server_start_config_thread(config, thread);
73.40 +}
73.41 +
73.42 +/* Complete initialisation of a server in the given thread. */
73.43 +
73.44 +long ipc_server_start_config_thread(ipc_server_config_type *config,
73.45 + l4_cap_idx_t thread)
73.46 +{
73.47 config->thread = thread;
73.48 config->config_thread = 1;
73.49
73.50 @@ -198,7 +212,7 @@
73.51 long ipc_server_managed_loop(int expected_items, ipc_server_config_type *config)
73.52 {
73.53 ipc_message_t msg;
73.54 - l4_umword_t label, irq_label = (l4_umword_t) config->irq;
73.55 + l4_umword_t label, irq_label;
73.56
73.57 /* Permit other endpoints by dynamically interpreting the label. */
73.58
73.59 @@ -211,11 +225,6 @@
73.60 if (err)
73.61 return err;
73.62
73.63 - /* Unmask the interrupt. */
73.64 -
73.65 - if (l4_is_valid_cap(config->irq))
73.66 - ipc_init_irq(config->irq);
73.67 -
73.68 /* Wait for an incoming message. */
73.69
73.70 while (1)
73.71 @@ -233,7 +242,9 @@
73.72
73.73 /* Message involves the IPC gate itself. */
73.74
73.75 - if (label != irq_label)
73.76 + irq_label = (l4_umword_t) config->irq;
73.77 +
73.78 + if (!config->notifications || (config->notifications && (label != irq_label)))
73.79 {
73.80 config_from_label = (ipc_server_config_type *) label;
73.81 config_from_label->handler(&msg, config_from_label->handler_obj);
73.82 @@ -241,7 +252,7 @@
73.83
73.84 /* Message involves the IRQ or a termination condition occurred. */
73.85
73.86 - if ((label == irq_label) || msg.terminating)
73.87 + else if ((config->notifications && (label == irq_label)) || msg.terminating)
73.88 break;
73.89 }
73.90
73.91 @@ -369,6 +380,10 @@
73.92
73.93 if (err)
73.94 return err;
73.95 +
73.96 + /* Unmask the interrupt. */
73.97 +
73.98 + ipc_init_irq(config->irq);
73.99 }
73.100
73.101 /* With a separate thread, return the last status value. Otherwise, invoke the
74.1 --- a/libipc/lib/src/util_ipc.c Sun Jun 12 17:10:30 2022 +0200
74.2 +++ b/libipc/lib/src/util_ipc.c Wed Aug 10 00:25:44 2022 +0200
74.3 @@ -30,7 +30,9 @@
74.4
74.5
74.6
74.7 -/* Declare expected capabilities. */
74.8 +/* Declare expected capabilities.
74.9 + NOTE: This does not support the mixing of expected capabilities and other
74.10 + items. */
74.11
74.12 long _expect_capabilities(l4_buf_regs_t *bregs, int number)
74.13 {
74.14 @@ -233,3 +235,6 @@
74.15 {
74.16 return l4_ipc_send(endpoint, l4_utcb(), tag, L4_IPC_NEVER);
74.17 }
74.18 +
74.19 +/* vim: tabstop=2 expandtab shiftwidth=2
74.20 +*/
75.1 --- a/libmem/Control Sun Jun 12 17:10:30 2022 +0200
75.2 +++ b/libmem/Control Wed Aug 10 00:25:44 2022 +0200
75.3 @@ -1,3 +1,3 @@
75.4 -requires: libstdc++ libc libsystypes
75.5 +requires: libstdc++ libc libsystypes libipc
75.6 provides: libmem
75.7 maintainer: paul@boddie.org.uk
76.1 --- a/libmem/include/mem/flexpage.h Sun Jun 12 17:10:30 2022 +0200
76.2 +++ b/libmem/include/mem/flexpage.h Wed Aug 10 00:25:44 2022 +0200
76.3 @@ -1,7 +1,7 @@
76.4 /*
76.5 * A flexpage abstraction.
76.6 *
76.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
76.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
76.9 *
76.10 * This program is free software; you can redistribute it and/or
76.11 * modify it under the terms of the GNU General Public License as
76.12 @@ -21,6 +21,10 @@
76.13
76.14 #pragma once
76.15
76.16 +#include <l4/re/c/dataspace.h>
76.17 +
76.18 +#include <list>
76.19 +
76.20 #include <mem/memory_utils.h>
76.21 #include <mem/region.h>
76.22 #include <mem/send_flexpage.h>
76.23 @@ -34,6 +38,16 @@
76.24
76.25
76.26
76.27 +/* Forward declaration. */
76.28 +
76.29 +class Flexpage;
76.30 +
76.31 +/* Employed data types. */
76.32 +
76.33 +typedef std::list<Flexpage *> DerivedFlexpages;
76.34 +
76.35 +
76.36 +
76.37 /* A flexpage abstraction. */
76.38
76.39 class Flexpage
76.40 @@ -45,6 +59,10 @@
76.41 public:
76.42 Region *region;
76.43
76.44 + /* Flexpage relationships to support masked regions. */
76.45 +
76.46 + DerivedFlexpages derived;
76.47 +
76.48 /* General flexpage characteristics. */
76.49
76.50 offset_t base_addr, size;
76.51 @@ -56,10 +74,15 @@
76.52
76.53 /* Associate a flexpage with a memory 'region'. */
76.54
76.55 - explicit Flexpage(Region *region) : region(region)
76.56 + explicit Flexpage(Region *region = NULL)
76.57 + : region(region)
76.58 {
76.59 }
76.60
76.61 + virtual ~Flexpage();
76.62 +
76.63 + void set_region(Region *region);
76.64 +
76.65 void reset(offset_t offset);
76.66
76.67 bool decrement();
76.68 @@ -80,6 +103,12 @@
76.69 offset_t max_offset=0);
76.70
76.71 SendFlexpage to_unmap();
76.72 +
76.73 + /* Associate other flexpages with this flexpage. */
76.74 +
76.75 + void associate(Flexpage *flexpage);
76.76 +
76.77 + void disassociate();
76.78 };
76.79
76.80 // vim: tabstop=4 expandtab shiftwidth=4
77.1 --- a/libmem/include/mem/memory_incremental.h Sun Jun 12 17:10:30 2022 +0200
77.2 +++ b/libmem/include/mem/memory_incremental.h Wed Aug 10 00:25:44 2022 +0200
77.3 @@ -1,7 +1,7 @@
77.4 /*
77.5 * A memory pool allocating a region at a time from the system.
77.6 *
77.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
77.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
77.9 *
77.10 * This program is free software; you can redistribute it and/or
77.11 * modify it under the terms of the GNU General Public License as
77.12 @@ -43,6 +43,8 @@
77.13
77.14 Region *allocate(offset_t size);
77.15
77.16 + void deallocate(Region *region);
77.17 +
77.18 public:
77.19 explicit MemoryIncremental(unsigned int limit, offset_t region_size=PAGE_SIZE);
77.20
78.1 --- a/libmem/include/mem/region.h Sun Jun 12 17:10:30 2022 +0200
78.2 +++ b/libmem/include/mem/region.h Wed Aug 10 00:25:44 2022 +0200
78.3 @@ -1,7 +1,7 @@
78.4 /*
78.5 * Memory region abstractions.
78.6 *
78.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
78.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
78.9 *
78.10 * This program is free software; you can redistribute it and/or
78.11 * modify it under the terms of the GNU General Public License as
78.12 @@ -59,8 +59,6 @@
78.13
78.14 explicit Region(offset_t start, offset_t end);
78.15
78.16 - virtual ~Region();
78.17 -
78.18 offset_t size();
78.19
78.20 int compare(Region *other);
79.1 --- a/libmem/lib/src/Makefile Sun Jun 12 17:10:30 2022 +0200
79.2 +++ b/libmem/lib/src/Makefile Wed Aug 10 00:25:44 2022 +0200
79.3 @@ -8,7 +8,7 @@
79.4 flexpage.cc memory_incremental.cc memory_preallocated.cc \
79.5 memory_utils.cc region.cc
79.6
79.7 -REQUIRES_LIBS = l4re_c-util libstdc++ libsystypes
79.8 +REQUIRES_LIBS = l4re_c-util libstdc++ libsystypes libipc
79.9
79.10 PRIVATE_INCDIR = $(PKGDIR)/include $(PKGDIR)/include/mem
79.11 CONTRIB_INCDIR = libmem
80.1 --- a/libmem/lib/src/flexpage.cc Sun Jun 12 17:10:30 2022 +0200
80.2 +++ b/libmem/lib/src/flexpage.cc Wed Aug 10 00:25:44 2022 +0200
80.3 @@ -1,7 +1,7 @@
80.4 /*
80.5 * A flexpage abstraction.
80.6 *
80.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
80.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
80.9 *
80.10 * This program is free software; you can redistribute it and/or
80.11 * modify it under the terms of the GNU General Public License as
80.12 @@ -19,18 +19,25 @@
80.13 * Boston, MA 02110-1301, USA
80.14 */
80.15
80.16 -#include <l4/re/c/dataspace.h>
80.17 -
80.18 #include <algorithm>
80.19
80.20 #include "flexpage.h"
80.21
80.22
80.23
80.24 +/* Virtual destructor required for introspection. */
80.25 +
80.26 +Flexpage::~Flexpage()
80.27 +{
80.28 +}
80.29 +
80.30 /* Reset the flexpage using 'offset', being the file offset. */
80.31
80.32 void Flexpage::reset(offset_t offset)
80.33 {
80.34 + if (region == NULL)
80.35 + return;
80.36 +
80.37 _counter = 0;
80.38 _flags = 0;
80.39
80.40 @@ -64,6 +71,13 @@
80.41 page_addr = base_addr + page_offset;
80.42 }
80.43
80.44 +/* Set a region. */
80.45 +
80.46 +void Flexpage::set_region(Region *region)
80.47 +{
80.48 + this->region = region;
80.49 +}
80.50 +
80.51 /* Decrement the usage counter, returning whether the flexpage is now no longer
80.52 used. */
80.53
80.54 @@ -156,12 +170,16 @@
80.55 if (!receive_size)
80.56 return SendFlexpage(base_addr, page_order(0), flags);
80.57
80.58 - offset_t receive_page_offset = hot_spot % receive_size;
80.59 + /* Employ the page-aligned hot spot for compatibility with the page
80.60 + offset, thus handling any non-aligned values sent in map requests. */
80.61 +
80.62 + offset_t hot_spot_page = trunc(hot_spot, PAGE_SIZE);
80.63 + offset_t receive_page_offset = hot_spot_page % receive_size;
80.64
80.65 while ((receive_size > PAGE_SIZE) && (receive_page_offset != page_offset))
80.66 {
80.67 receive_size /= 2;
80.68 - receive_page_offset = hot_spot % receive_size;
80.69 + receive_page_offset = hot_spot_page % receive_size;
80.70 }
80.71
80.72 /* The flexpage base address is adjusted using the difference in page
80.73 @@ -180,4 +198,16 @@
80.74 return SendFlexpage(base_addr, page_order(size), _flags);
80.75 }
80.76
80.77 +/* Associate another flexpage with this flexpage. */
80.78 +
80.79 +void Flexpage::associate(Flexpage *flexpage)
80.80 +{
80.81 + derived.push_back(flexpage);
80.82 +}
80.83 +
80.84 +void Flexpage::disassociate()
80.85 +{
80.86 + derived.clear();
80.87 +}
80.88 +
80.89 // vim: tabstop=4 expandtab shiftwidth=4
81.1 --- a/libmem/lib/src/memory_incremental.cc Sun Jun 12 17:10:30 2022 +0200
81.2 +++ b/libmem/lib/src/memory_incremental.cc Wed Aug 10 00:25:44 2022 +0200
81.3 @@ -1,7 +1,7 @@
81.4 /*
81.5 * A memory pool allocating a region at a time from the system.
81.6 *
81.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
81.8 + * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk>
81.9 *
81.10 * This program is free software; you can redistribute it and/or
81.11 * modify it under the terms of the GNU General Public License as
81.12 @@ -21,6 +21,8 @@
81.13
81.14 #include "memory_incremental.h"
81.15
81.16 +#include <ipc/mem_ipc.h>
81.17 +
81.18 #include <stdlib.h>
81.19
81.20
81.21 @@ -45,18 +47,31 @@
81.22 {
81.23 /* Attempt to allocate aligned memory. */
81.24
81.25 - void *current;
81.26 + void *current = NULL;
81.27 + l4re_ds_t ds;
81.28
81.29 /* Make the size appropriate for the invocation. */
81.30
81.31 size = round_multiple(size, PAGE_SIZE);
81.32
81.33 - if (posix_memalign(¤t, size, size))
81.34 + /* Use allocation permitting executable mapping of the memory.
81.35 + NOTE: Here, it might be beneficial to employ an allocator that obtains
81.36 + dataspaces and provides multiple blocks from each dataspace. */
81.37 +
81.38 + if (ipc_allocate_align(size, L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RWX, page_order(size), ¤t, &ds))
81.39 return NULL;
81.40
81.41 return new Region((offset_t) current, (offset_t) current + size);
81.42 }
81.43
81.44 +/* Deallocate the given region. */
81.45 +
81.46 +void MemoryIncremental::deallocate(Region *region)
81.47 +{
81.48 + ipc_detach_dataspace((void *) region->start);
81.49 + delete region;
81.50 +}
81.51 +
81.52 /* Allocate a new region of the given 'size' rounded to the nearest page. */
81.53
81.54 Region *MemoryIncremental::region(offset_t size)
81.55 @@ -109,7 +124,7 @@
81.56 if (_limited)
81.57 _limit += pages;
81.58
81.59 - delete region;
81.60 + deallocate(region);
81.61 }
81.62
81.63 // vim: tabstop=4 expandtab shiftwidth=4
82.1 --- a/libmem/lib/src/region.cc Sun Jun 12 17:10:30 2022 +0200
82.2 +++ b/libmem/lib/src/region.cc Wed Aug 10 00:25:44 2022 +0200
82.3 @@ -58,13 +58,6 @@
82.4 memset((void *) start, 0, end - start);
82.5 }
82.6
82.7 -/* Deallocate the region, freeing its memory. */
82.8 -
82.9 -Region::~Region()
82.10 -{
82.11 - free((void *) start);
82.12 -}
82.13 -
82.14 /* Return the size of the region. */
82.15
82.16 offset_t Region::size()
83.1 --- a/libsystypes/Control Sun Jun 12 17:10:30 2022 +0200
83.2 +++ b/libsystypes/Control Wed Aug 10 00:25:44 2022 +0200
83.3 @@ -1,2 +1,3 @@
83.4 provides: libsystypes
83.5 +requires: l4re_c-util
83.6 maintainer: paul@boddie.org.uk
85.1 --- a/libsystypes/idl/mapped_file.idl Sun Jun 12 17:10:30 2022 +0200
85.2 +++ b/libsystypes/idl/mapped_file.idl Wed Aug 10 00:25:44 2022 +0200
85.3 @@ -4,10 +4,12 @@
85.4
85.5 interface MappedFile
85.6 {
85.7 - /* Memory-map a file for the given file position and length, obtaining the
85.8 - limits of the mapped region and the size of the file. */
85.9 + /* Memory-map a file for the given file position and length, masking regions
85.10 + beyond any visible range if indicated, obtaining the limits of the mapped
85.11 + region and the size of the file. */
85.12
85.13 [opcode(7)] void mmap(in offset_t position, in offset_t length,
85.14 + in offset_t start_visible, in offset_t end_visible,
85.15 out offset_t start_pos, out offset_t end_pos,
85.16 out offset_t size);
85.17 };
86.1 --- a/libsystypes/include/systypes/base.h Sun Jun 12 17:10:30 2022 +0200
86.2 +++ b/libsystypes/include/systypes/base.h Wed Aug 10 00:25:44 2022 +0200
86.3 @@ -1,7 +1,7 @@
86.4 /*
86.5 * Base types used by various other types.
86.6 *
86.7 - * Copyright (C) 2019, 2021 Paul Boddie <paul@boddie.org.uk>
86.8 + * Copyright (C) 2019, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
86.9 *
86.10 * This program is free software; you can redistribute it and/or
86.11 * modify it under the terms of the GNU General Public License as
86.12 @@ -63,6 +63,19 @@
86.13 OBJECT_HAS_SIZE = 2
86.14 };
86.15
86.16 +/* Memory mapping protection flags compatible with sys/mman.h (and incompatible
86.17 + with comparable L4Re flags). */
86.18 +
86.19 +typedef unsigned long prot_t;
86.20 +
86.21 +enum prot_flags
86.22 +{
86.23 + PROT_NONE = 0,
86.24 + PROT_READ = 1,
86.25 + PROT_WRITE = 2,
86.26 + PROT_EXEC = 4
86.27 +};
86.28 +
86.29 /* Equivalent types are defined in sys/types.h typically. In newlib, they are
86.30 defined in sys/_types.h if not defined elsewhere (such as in
86.31 machine/_types.h).
87.1 --- a/test_files/Control Sun Jun 12 17:10:30 2022 +0200
87.2 +++ b/test_files/Control Wed Aug 10 00:25:44 2022 +0200
87.3 @@ -1,3 +1,3 @@
87.4 provides: fstest_files
87.5 -requires: libc
87.6 +requires: libc libstdc++ libexec libipc
87.7 maintainer: paul@boddie.org.uk
88.1 --- a/test_files/Makefile Sun Jun 12 17:10:30 2022 +0200
88.2 +++ b/test_files/Makefile Wed Aug 10 00:25:44 2022 +0200
88.3 @@ -4,18 +4,32 @@
88.4 E2ACCESS_DIR = $(PKGDIR)/../libe2access/host
88.5 TARGET = $(PKGDIR)/../conf/e2test.fs
88.6
88.7 +REQUIRES_LIBS = libc libstdc++ libexec libipc
88.8 +
88.9 include $(L4DIR)/mk/Makeconf
88.10 -include $(OBJ_BASE)/l4defs.mk.inc
88.11 +
88.12 +# Attempt to define system details manually, since the following will not work
88.13 +# until a complete build has been performed.
88.14 +#
88.15 +#include $(OBJ_BASE)/l4defs.mk.inc
88.16 +
88.17 +L4_SYSTEM = $(BUILD_ARCH)_$(CPU)
88.18
88.19 PROGRAMS_DIR = $(PKGDIR_OBJ)/programs/OBJ-$(L4_SYSTEM)-l4f
88.20
88.21 +LIBEXEC_DIR = $(PKGDIR)/../libexec
88.22 +RM_PROGRAM_DIR = $(call absfilename,$(OBJ_DIR)/$(LIBEXEC_DIR))/rm/OBJ-$(L4_SYSTEM)-l4f
88.23 +RM_PROGRAM = $(RM_PROGRAM_DIR)/exec_region_mapper
88.24 +
88.25 # Special rules to build the test filesystem.
88.26
88.27 all:: $(TARGET) $(PROGRAMS_DIR)
88.28
88.29 -$(TARGET): $(PROGRAMS_DIR)
88.30 +$(TARGET): $(PROGRAMS_DIR) $(RM_PROGRAM)
88.31 $(MAKE) -C $(E2ACCESS_DIR) && \
88.32 - $(PKGDIR)/mk_e2test.sh -q $(PKGDIR) $(PROGRAMS_DIR) $(E2ACCESS_DIR) $@
88.33 + $(PKGDIR)/mk_e2test.sh -q $(PKGDIR) $(E2ACCESS_DIR) $@ \
88.34 + $(PROGRAMS_DIR)/dstest_* \
88.35 + $(RM_PROGRAM)
88.36
88.37 $(PROGRAMS_DIR): $(PKGDIR)/programs/*.c*
88.38 $(MAKE) -C $(PKGDIR)/programs $(MKFLAGS) && \
89.1 --- a/test_files/mk_e2test.sh Sun Jun 12 17:10:30 2022 +0200
89.2 +++ b/test_files/mk_e2test.sh Wed Aug 10 00:25:44 2022 +0200
89.3 @@ -31,18 +31,19 @@
89.4 fi
89.5
89.6 PKGDIR=$(realpath "$1")
89.7 -PROGRAMS_DIR=$(realpath "$2")
89.8 -E2ACCESS_DIR=$(realpath "$3")
89.9 -TARGET=$(realpath "$4")
89.10 +E2ACCESS_DIR=$(realpath "$2")
89.11 +TARGET=$(realpath "$3")
89.12
89.13 -if [ ! -e "$PKGDIR" ] || [ ! -e "$PROGRAMS_DIR" ] || [ ! -e "$E2ACCESS_DIR" ] || [ ! "$TARGET" ] ; then
89.14 +shift 3
89.15 +
89.16 +if [ ! -e "$PKGDIR" ] || [ ! -e "$E2ACCESS_DIR" ] || [ ! "$TARGET" ] ; then
89.17 cat 1>&2 <<EOF
89.18 -Usage: $PROGNAME [ -q ] <package directory> <programs directory> <e2access directory> <target>
89.19 +Usage: $PROGNAME [ -q ] <package directory> <e2access directory> <target> [ <program> ... ]
89.20
89.21 Package directory: $PKGDIR
89.22 -Programs directory: $PROGRAMS_DIR
89.23 e2access directory: $E2ACCESS_DIR
89.24 Target filesystem: $TARGET
89.25 +Programs: $*
89.26 EOF
89.27 exit 1
89.28 fi
89.29 @@ -110,7 +111,9 @@
89.30
89.31 # Put some programs in the same place.
89.32
89.33 -cp "$PROGRAMS_DIR/dstest_"* .
89.34 +for PROGRAM in $* ; do
89.35 + cp $(realpath "$PROGRAM") .
89.36 +done
89.37
89.38 # Leave the filesystem root.
89.39
91.1 --- a/tests/Makefile Sun Jun 12 17:10:30 2022 +0200
91.2 +++ b/tests/Makefile Wed Aug 10 00:25:44 2022 +0200
91.3 @@ -9,12 +9,14 @@
91.4 dstest_file_monitor \
91.5 dstest_file_readdir \
91.6 dstest_file_readdir_concurrent \
91.7 + dstest_file_remove \
91.8 dstest_file_rename \
91.9 dstest_host_client \
91.10 dstest_pipe_client \
91.11 dstest_test_client \
91.12 dstest_map_test \
91.13 - dstest_exec
91.14 + dstest_exec \
91.15 + dstest_file_mapping
91.16
91.17 MODE = static
91.18
91.19 @@ -29,18 +31,22 @@
91.20
91.21 # Compound interfaces.
91.22
91.23 -pager_object_NAME = PagerObject
91.24 -pager_object_INTERFACES = region_mapper system_pager
91.25 +pager_object_NAME = PagerObject
91.26 +pager_object_INTERFACES = region_mapper system_pager
91.27
91.28 -COMP_INTERFACES_CC = pager_object
91.29 +COMP_INTERFACES_CC = pager_object
91.30
91.31 # Individual interfaces.
91.32
91.33 -SERVER_INTERFACES_CC = $(call common_interfaces,$(COMP_INTERFACES_CC))
91.34 +CLIENT_INTERFACES_CC = dataspace
91.35 +
91.36 +SERVER_INTERFACES_CC = $(call common_interfaces,$(COMP_INTERFACES_CC))
91.37
91.38 # Generated and plain source files.
91.39
91.40 -SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC) $(COMP_INTERFACES_CC))
91.41 +CLIENT_INTERFACES_SRC_CC = $(call interfaces_to_client_cc,$(CLIENT_INTERFACES_CC))
91.42 +
91.43 +SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC) $(COMP_INTERFACES_CC))
91.44
91.45 # Normal source files.
91.46
91.47 @@ -60,6 +66,8 @@
91.48
91.49 SRC_CC_dstest_file_readdir_concurrent = dstest_file_readdir_concurrent.cc
91.50
91.51 +SRC_CC_dstest_file_remove = dstest_file_remove.cc
91.52 +
91.53 SRC_CC_dstest_file_rename = dstest_file_rename.cc
91.54
91.55 SRC_CC_dstest_host_client = dstest_host_client.cc
91.56 @@ -71,6 +79,9 @@
91.57 PLAIN_SRC_CC_dstest_exec = dstest_exec.cc
91.58 SRC_CC_dstest_exec = $(PLAIN_SRC_CC_dstest_exec) $(SERVER_INTERFACES_SRC_CC)
91.59
91.60 +PLAIN_SRC_CC_dstest_file_mapping = dstest_file_mapping.cc
91.61 +SRC_CC_dstest_file_mapping = $(PLAIN_SRC_CC_dstest_file_mapping) $(CLIENT_INTERFACES_SRC_CC)
91.62 +
91.63 REQUIRES_LIBS = l4re_c-util libexec libfsclient libmem libipc libstdc++ libsystypes libe2access_blockserver
91.64 PRIVATE_INCDIR = $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR)
91.65
91.66 @@ -78,3 +89,5 @@
91.67 include $(IDL_MK_DIR)/interface_rules.mk
91.68
91.69 $(PLAIN_SRC_CC_dstest_exec): $(SERVER_INTERFACES_SRC_CC)
91.70 +
91.71 +$(PLAIN_SRC_CC_dstest_file_mapping): $(CLIENT_INTERFACES_SRC_CC)
92.1 --- a/tests/dstest_block_client.cc Sun Jun 12 17:10:30 2022 +0200
92.2 +++ b/tests/dstest_block_client.cc Wed Aug 10 00:25:44 2022 +0200
92.3 @@ -1,7 +1,7 @@
92.4 /*
92.5 * Test dataspace operations.
92.6 *
92.7 - * Copyright (C) 2020, 2021 Paul Boddie <paul@boddie.org.uk>
92.8 + * Copyright (C) 2020, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
92.9 *
92.10 * This program is free software; you can redistribute it and/or
92.11 * modify it under the terms of the GNU General Public License as
92.12 @@ -45,9 +45,24 @@
92.13 unsigned long sample_remaining = remaining < sample ? remaining : sample;
92.14
92.15 printf("%ld bytes from %p...\n", sample_remaining, (file->memory + offset));
92.16 - strncpy(buf, (file->memory + offset), sample_remaining);
92.17 + memcpy(buf, (file->memory + offset), sample_remaining);
92.18 buf[sample_remaining] = '\0';
92.19 - printf("%s\n", buf);
92.20 +
92.21 + unsigned long leading = 0;
92.22 + char *outbuf = buf;
92.23 +
92.24 + while ((*outbuf == '\0') && (leading < sample_remaining))
92.25 + {
92.26 + outbuf++;
92.27 + leading++;
92.28 + }
92.29 +
92.30 + if (leading)
92.31 + printf("[%ld zero bytes]\n", leading);
92.32 +
92.33 + printf("%s\n", outbuf);
92.34 +
92.35 + printf("[%ld bytes after string]\n", sample_remaining - leading - strlen(outbuf));
92.36 }
92.37 }
92.38
92.39 @@ -80,9 +95,10 @@
92.40 return 1;
92.41 }
92.42
92.43 - /* A region of the file is mapped. */
92.44 + /* A region of the file is mapped. Here, the start and length will not provide
92.45 + page-aligned offsets, but the region is nevertheless not masked. */
92.46
92.47 - err = file_mmap(&file, 0, page(10));
92.48 + err = file_mmap(&file, 10, 290, 0, 0, file_region_flags(file.flags));
92.49
92.50 if (err)
92.51 {
92.52 @@ -90,16 +106,39 @@
92.53 return 1;
92.54 }
92.55
92.56 + printf("File contents:\n");
92.57 +
92.58 show(&file, step, sample);
92.59
92.60 + printf("File shown.\n");
92.61 +
92.62 + /* A region of the file is mapped. Here, the resulting offsets will be used to
92.63 + define a masked region. */
92.64 +
92.65 + err = file_mmap(&file, 10, 290, 10, 290, file_region_flags(file.flags));
92.66 +
92.67 + if (err)
92.68 + {
92.69 + printf("Could not map file region: %s\n", l4sys_errtostr(err));
92.70 + return 1;
92.71 + }
92.72 +
92.73 + printf("File contents:\n");
92.74 +
92.75 + show(&file, step, sample);
92.76 +
92.77 + printf("File shown.\n");
92.78 +
92.79 /* Resizing must occur before writing beyond the end of file. Otherwise, the
92.80 data may get discarded if the supporting flexpage needs to be flushed. */
92.81
92.82 - offset_t new_region = round(file_populated_span(&file), page(1));
92.83 + offset_t old_size = file_populated_span(&file);
92.84 + offset_t new_region = round(old_size, page(1));
92.85 + offset_t new_size = new_region + old_size;
92.86
92.87 - printf("Resize to %ld...\n", new_region + file_populated_span(&file));
92.88 + printf("Resize to %ld...\n", new_size);
92.89
92.90 - err = file_resize(&file, new_region + file_populated_span(&file));
92.91 + err = file_resize(&file, new_size);
92.92
92.93 if (err)
92.94 {
92.95 @@ -109,17 +148,46 @@
92.96
92.97 printf("Resized file...\n");
92.98
92.99 + /* Re-map to avoid masking the region. */
92.100 +
92.101 + err = file_mmap(&file, 10, new_size - 20, 0, 0, file_region_flags(file.flags));
92.102 +
92.103 + if (err)
92.104 + {
92.105 + printf("Could not map file region: %s\n", l4sys_errtostr(err));
92.106 + return 1;
92.107 + }
92.108 +
92.109 /* Copy the sampled data to another file region. */
92.110
92.111 printf("Copy data to %ld...\n", new_region);
92.112
92.113 - for (unsigned long offset = 0; offset < file_populated_span(&file); offset += step)
92.114 + for (unsigned long offset = 0; offset < old_size; offset += step)
92.115 {
92.116 + printf("Copying to %ld...\n", new_region + offset);
92.117 memcpy(file.memory + new_region + offset, file.memory + offset, sample);
92.118 if (step > sample)
92.119 memset(file.memory + new_region + offset + sample, 0, step - sample);
92.120 }
92.121
92.122 + printf("File contents:\n");
92.123 +
92.124 + show(&file, step, sample);
92.125 +
92.126 + printf("File shown.\n");
92.127 +
92.128 + /* Re-map to mask the region again. */
92.129 +
92.130 + err = file_mmap(&file, 0, new_size, 10, new_size - 20, file_region_flags(file.flags));
92.131 +
92.132 + if (err)
92.133 + {
92.134 + printf("Could not map file region: %s\n", l4sys_errtostr(err));
92.135 + return 1;
92.136 + }
92.137 +
92.138 + printf("File contents:\n");
92.139 +
92.140 show(&file, step, sample);
92.141
92.142 printf("File shown.\n");
93.1 --- a/tests/dstest_exec.cc Sun Jun 12 17:10:30 2022 +0200
93.2 +++ b/tests/dstest_exec.cc Wed Aug 10 00:25:44 2022 +0200
93.3 @@ -20,291 +20,52 @@
93.4 */
93.5
93.6 #include <l4/re/env.h>
93.7 -#include <l4/re/l4aux.h>
93.8 #include <l4/sys/err.h>
93.9 -#include <l4/util/elf.h>
93.10 #include <l4/util/util.h>
93.11
93.12 #include <exec/elf.h>
93.13 +#include <exec/external_pager.h>
93.14 +#include <exec/memory.h>
93.15 #include <exec/process.h>
93.16 -#include <fsclient/client.h>
93.17 -#include <ipc/mem_ipc.h>
93.18 +#include <ipc/cap_alloc.h>
93.19 +#include <ipc/map.h>
93.20 #include <ipc/server.h>
93.21 -#include <mem/memory_utils.h>
93.22 -#include <systypes/fcntl.h>
93.23 -
93.24 -#include <map>
93.25
93.26 #include <stdio.h>
93.27 -#include <stdlib.h>
93.28 -#include <string.h>
93.29
93.30 #include <pthread-l4.h>
93.31 #include <pthread.h>
93.32
93.33 -#include "pager_object_interface.h"
93.34 #include "pager_object_server.h"
93.35
93.36
93.37
93.38 -/* A simple system pager also acting as a region mapper. */
93.39 -
93.40 -typedef std::map<l4_addr_t, MappedRegion> MappedRegions;
93.41 -
93.42 -class ExecPager : public PagerObject
93.43 -{
93.44 -protected:
93.45 - MappedRegions _regions;
93.46 -
93.47 -public:
93.48 - virtual void add(MappedRegion region)
93.49 - {
93.50 - _regions[region.map_start] = region;
93.51 - }
93.52 -
93.53 - /* Notification methods. */
93.54 -
93.55 - virtual long exception(l4_exc_regs_t regs,
93.56 - l4_snd_fpage_t *region);
93.57 -
93.58 - virtual long page_fault(l4_umword_t pfa, l4_umword_t pc,
93.59 - l4_snd_fpage_t *region);
93.60 -
93.61 - /* Region manager/mapper methods. */
93.62 -
93.63 - virtual long attach(address_t *start, offset_t size, map_flags_t flags,
93.64 - l4_cap_idx_t ds, address_t offset, unsigned char align);
93.65 -
93.66 -};
93.67 -
93.68 -/* Handle a general exception. */
93.69 -
93.70 -long ExecPager::exception(l4_exc_regs_t regs, l4_snd_fpage_t *region)
93.71 -{
93.72 - (void) region;
93.73 -
93.74 - printf("exception(...) -> pfa = %lx, pc = %lx\n", l4_utcb_exc_pfa(®s), l4_utcb_exc_pc(®s));
93.75 -
93.76 - printf("r15 = %lx\n", regs.r15);
93.77 - printf("r14 = %lx\n", regs.r14);
93.78 - printf("r13 = %lx\n", regs.r13);
93.79 - printf("r12 = %lx\n", regs.r12);
93.80 - printf("r11 = %lx\n", regs.r11);
93.81 - printf("r10 = %lx\n", regs.r10);
93.82 - printf("r9 = %lx\n", regs.r9);
93.83 - printf("r8 = %lx\n", regs.r8);
93.84 - printf("rdi = %lx\n", regs.rdi);
93.85 - printf("rsi = %lx\n", regs.rsi);
93.86 - printf("rbp = %lx\n", regs.rbp);
93.87 - printf("pfa = %lx\n", regs.pfa);
93.88 - printf("rbx = %lx\n", regs.rbx);
93.89 - printf("rdx = %lx\n", regs.rdx);
93.90 - printf("rcx = %lx\n", regs.rcx);
93.91 - printf("rax = %lx\n", regs.rax);
93.92 - printf("trapno = %lx\n", regs.trapno);
93.93 - printf("err = %lx\n", regs.err);
93.94 - printf("ip = %lx\n", regs.ip);
93.95 - printf("flags = %lx\n", regs.flags);
93.96 - printf("sp = %lx\n", regs.sp);
93.97 - printf("ss = %lx\n", regs.ss);
93.98 - printf("fs_base = %lx\n", regs.fs_base);
93.99 - printf("gs_base = %lx\n", regs.gs_base);
93.100 -
93.101 - return L4_EOK;
93.102 -}
93.103 -
93.104 -#define DEBUG 0
93.105 -
93.106 -/* Handle a page fault using any configured regions. */
93.107 -
93.108 -long ExecPager::page_fault(l4_umword_t pfa, l4_umword_t pc, l4_snd_fpage_t *region)
93.109 -{
93.110 - l4_umword_t addr = pfa & ~7UL, flags = pfa & 7;
93.111 -
93.112 -#if DEBUG
93.113 - printf("page_fault(%lx, %lx) -> %lx (%lx) -> ", pfa, pc, addr, flags);
93.114 -#endif
93.115 -
93.116 - MappedRegions::iterator it = _regions.upper_bound(addr);
93.117 -
93.118 - if (it != _regions.begin())
93.119 - it--;
93.120 - else
93.121 - {
93.122 - printf("not mapped!\n");
93.123 - return -L4_ENOMEM;
93.124 - }
93.125 -
93.126 - MappedRegion &r = it->second;
93.127 -
93.128 - if ((addr >= r.map_start) && (addr < r.map_start + r.size))
93.129 - {
93.130 - l4_addr_t page_addr = trunc(addr, L4_PAGESIZE);
93.131 -
93.132 - region->fpage = l4_fpage(r.start + (page_addr - r.map_start), L4_PAGESHIFT, r.flags);
93.133 - region->snd_base = page_addr;
93.134 -
93.135 -#if DEBUG
93.136 - printf("%lx...%lx from %lx...%lx offset %lx size %d rights %x\n",
93.137 - r.map_start, region->snd_base,
93.138 - r.start, l4_fpage_memaddr(region->fpage),
93.139 - addr - r.map_start,
93.140 - l4_fpage_size(region->fpage),
93.141 - l4_fpage_rights(region->fpage));
93.142 -
93.143 - printf("%lx -> ", addr);
93.144 -
93.145 - for (unsigned int i = 0; i < sizeof(l4_umword_t); i++)
93.146 - printf("%02x", *((unsigned char *)(r.start + (addr - r.map_start) + i)));
93.147 -
93.148 - printf("\n");
93.149 -#endif
93.150 -
93.151 - if (r.flags & L4RE_RM_F_W)
93.152 - l4_touch_rw((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE);
93.153 - else
93.154 - l4_touch_ro((const void *) (r.start + (page_addr - r.map_start)), L4_PAGESIZE);
93.155 +/* External system-level pager for the region mapper in a created task. */
93.156
93.157 - return L4_EOK;
93.158 - }
93.159 -
93.160 -#if DEBUG
93.161 - printf("not mapped!\n");
93.162 -#endif
93.163 -
93.164 - return -L4_ENOMEM;
93.165 -}
93.166 -
93.167 -/* Attach a region for provision when page faults occur. This is required in
93.168 - the initialisation of a program by the C library which requires a region
93.169 - mapper. */
93.170 -
93.171 -long ExecPager::attach(address_t *start, offset_t size, map_flags_t flags,
93.172 - l4_cap_idx_t ds, address_t offset, unsigned char align)
93.173 -{
93.174 -#if DEBUG
93.175 - printf("attach(%lx, %ld, %lx, ..., %lx, %d)\n", *start, size, flags, offset, align);
93.176 -#endif
93.177 -
93.178 - if (align < L4_PAGESHIFT)
93.179 - align = L4_PAGESHIFT;
93.180 -
93.181 - offset_t increment = 1UL << align;
93.182 - offset_t region_size = round(size, increment);
93.183 -
93.184 - /* Either attempt to find an address for the specified region, starting from
93.185 - any indicated address. */
93.186 -
93.187 - if (flags & L4RE_RM_F_SEARCH_ADDR)
93.188 - {
93.189 - address_t region_start = trunc(*start, increment);
93.190 - MappedRegions::iterator it = _regions.upper_bound(*start);
93.191 -
93.192 - if (!region_start)
93.193 - region_start += increment;
93.194 -
93.195 -#if DEBUG
93.196 - printf("-> search from %lx -> %lx...\n", *start, region_start);
93.197 -#endif
93.198 -
93.199 - /* Before last known region. */
93.200 -
93.201 - while (it != _regions.end())
93.202 - {
93.203 - MappedRegions::iterator next = it;
93.204 - MappedRegion &r = it->second;
93.205 - address_t start_limit;
93.206 - address_t end_limit = r.map_start;
93.207 -
93.208 - /* Consider any preceding region. If no such region exists, choose an
93.209 - address at the start of memory. */
93.210 +static ExternalPager exec_pager;
93.211
93.212 - if (it == _regions.begin())
93.213 - start_limit = L4_PAGESIZE;
93.214 - else
93.215 - {
93.216 - it--;
93.217 - MappedRegion &pr = it->second;
93.218 - start_limit = pr.map_start + pr.size;
93.219 - it = next;
93.220 - }
93.221 -
93.222 - /* Test against the limits. */
93.223 -
93.224 - if (region_start < start_limit)
93.225 - region_start = round(start_limit, increment);
93.226 -
93.227 - /* Investigate subsequent regions if not enough space exists between the
93.228 - preceding region (or start of memory) and the current region. */
93.229 -
93.230 - if ((region_start + region_size) > end_limit)
93.231 - {
93.232 - it++;
93.233 - if (it == _regions.end())
93.234 - return -L4_ENOMEM;
93.235 - }
93.236 - else
93.237 - break;
93.238 - }
93.239 -
93.240 - /* Attach the provided dataspace.
93.241 - NOTE: This is only done in this implementation to support the paging
93.242 - mechanism. In a region mapper residing within the actual task, the
93.243 - dataspace's map operation would be invoked to obtain mappings. */
93.244 -
93.245 - l4_addr_t ds_start;
93.246 -
93.247 - long err = ipc_attach_dataspace(ds, size, (void **) &ds_start);
93.248 -
93.249 - if (err)
93.250 - return err;
93.251 -
93.252 - l4_touch_rw((const void *) ds_start, size);
93.253 -
93.254 -#if DEBUG
93.255 - printf("-> added region for %lx size %ld (%d)\n", region_start, region_size, page_order(region_size));
93.256 -#endif
93.257 -
93.258 - add(MappedRegion(ds_start, region_size, flags & L4RE_DS_F_RIGHTS_MASK, region_start));
93.259 -
93.260 - *start = region_start;
93.261 - return L4_EOK;
93.262 - }
93.263 -
93.264 - /* Or attempt to add the specified region at a specific address. */
93.265 -
93.266 - else
93.267 - {
93.268 - // NOTE: To be implemented.
93.269 -
93.270 -#if DEBUG
93.271 - printf("-> region of size %ld (%d) not added!\n", region_size, page_order(region_size));
93.272 -#endif
93.273 -
93.274 - return -L4_ENOMEM;
93.275 - }
93.276 -}
93.277 +static const offset_t initial_stack_size = 16 * L4_PAGESIZE;
93.278
93.279
93.280
93.281 -static ExecPager exec_pager;
93.282 +/* Start the system pager in a separate thread. */
93.283
93.284 -static void init_pager(ipc_server_config_type *config)
93.285 +static long start_pager(ipc_server_config_type &config)
93.286 {
93.287 - ipc_server_init_config(config);
93.288 + pthread_t pager_thread;
93.289 + pthread_attr_t attr;
93.290
93.291 - config->expected_items = PagerObject_expected_items;
93.292 - config->handler = (ipc_server_handler_type) handle_PagerObject;
93.293 - config->handler_obj = static_cast<PagerObject *>(&exec_pager);
93.294 -}
93.295 + pthread_attr_init(&attr);
93.296 + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
93.297 +
93.298 + ipc_server_init_for(&config, PagerObject, &exec_pager);
93.299
93.300 -static long start_pager(ipc_server_config_type *config, pthread_t thread)
93.301 -{
93.302 - config->config_thread = 1;
93.303 - config->thread = pthread_l4_cap(thread);
93.304 + long err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &config);
93.305
93.306 - printf("Starting pager thread...\n");
93.307 - return ipc_server_start_config(config);
93.308 + if (err)
93.309 + return err;
93.310 +
93.311 + return ipc_server_start_config_thread(&config, pthread_l4_cap(pager_thread));
93.312 }
93.313
93.314
93.315 @@ -313,170 +74,71 @@
93.316 {
93.317 long err;
93.318
93.319 - if (argc < 2)
93.320 + if (argc < 3)
93.321 {
93.322 - printf("Need a program to run.\n");
93.323 - return 1;
93.324 - }
93.325 -
93.326 - /* Obtain the payload as a dataspace. */
93.327 -
93.328 - file_t *file = client_open(argv[1], O_RDONLY);
93.329 -
93.330 - if (file == NULL)
93.331 - {
93.332 - printf("Could not read file: %s\n", argv[1]);
93.333 + printf("Need a program to run as the region mapper and a main program.\n");
93.334 return 1;
93.335 }
93.336
93.337 - /* Obtain metadata from the file. */
93.338 + /* Define the different payloads. */
93.339
93.340 - char buf[4096];
93.341 - offset_t nread;
93.342 + char *rm_filename = argv[1];
93.343 + char *program_filename = argv[2];
93.344
93.345 - nread = client_read(file, buf, EI_NIDENT);
93.346 - if ((nread < EI_NIDENT) || memcmp(buf, "\x7f" "ELF", 4))
93.347 + /* Initialise the memory segments of the region mapper. These are mapped into
93.348 + this task so that we may access them. */
93.349 +
93.350 + ExplicitSegment rm_stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW);
93.351 + Payload *rm_payload;
93.352 +
93.353 + if (exec_get_payload(rm_filename, &rm_payload, true))
93.354 {
93.355 - printf("Not an ELF payload: %s\n", argv[1]);
93.356 + printf("Could not initialise region mapper: %s\n", rm_filename);
93.357 return 1;
93.358 }
93.359
93.360 - Payload *payload = get_payload(buf);
93.361 -
93.362 - if (payload == NULL)
93.363 - {
93.364 - printf("Unrecognised object size.\n");
93.365 - return 1;
93.366 - }
93.367 -
93.368 - client_seek(file, 0, SEEK_SET);
93.369 - nread = client_read(file, buf, payload->header_extent());
93.370 -
93.371 - if (nread < payload->header_extent())
93.372 + if (rm_stack.allocate(true))
93.373 {
93.374 - printf("Header incomplete.\n");
93.375 - return 1;
93.376 - }
93.377 -
93.378 - printf("Program start: %lx\n", payload->entry_point());
93.379 -
93.380 - client_seek(file, 0, SEEK_SET);
93.381 - nread = client_read(file, buf, payload->program_header_extent());
93.382 -
93.383 - if (nread < payload->program_header_extent())
93.384 - {
93.385 - printf("Program headers incomplete.\n");
93.386 + printf("Could not allocate region mapper stack.\n");
93.387 return 1;
93.388 }
93.389
93.390 - /* Make appropriate segments, although program segments could be made
93.391 - interoperable with these. */
93.392 -
93.393 - Segment *segments[payload->segments() + 1];
93.394 -
93.395 - for (unsigned int i = 0; i < payload->segments(); i++)
93.396 - {
93.397 - ProgramSegment *ps = payload->segment(i);
93.398 -
93.399 - printf("Segment(0x%lx, 0x%lx, 0x%x, 0x%lx, 0x%lx): %s\n",
93.400 - ps->region_address(),
93.401 - ps->region_size(),
93.402 - ps->region_flags(),
93.403 - ps->file_offset(),
93.404 - ps->file_contents(),
93.405 - ps->loadable() ? "loadable" : "other");
93.406 -
93.407 - if (ps->loadable())
93.408 - segments[i] = ps->segment();
93.409 - else
93.410 - segments[i] = NULL;
93.411 - }
93.412 -
93.413 - /* Copy the payload regions to new dataspaces. */
93.414 -
93.415 - address_t program_start = payload->entry_point();
93.416 - offset_t initial_stack_size = 16 * L4_PAGESIZE;
93.417 -
93.418 - Segment stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW);
93.419 -
93.420 - segments[payload->segments()] = &stack;
93.421 -
93.422 - for (unsigned int i = 0; i < payload->segments() + 1; i++)
93.423 - {
93.424 - Segment *segment = segments[i];
93.425 -
93.426 - if (segment == NULL)
93.427 - continue;
93.428 -
93.429 - if (segment->file_contents())
93.430 - {
93.431 - flags_t flags;
93.432 -
93.433 - if ((segment->region_flags() & L4RE_RM_F_RW) == L4RE_RM_F_RW)
93.434 - flags = O_RDWR;
93.435 - else if (segment->region_flags() & L4RE_RM_F_W)
93.436 - flags = O_WRONLY;
93.437 - else
93.438 - flags = O_RDONLY;
93.439 -
93.440 - file_t *file = client_open(argv[1], flags);
93.441 + /* Initialise the memory segments of the actual program. These are not mapped
93.442 + into this task, instead being accessed by the region mapper in the new
93.443 + task. */
93.444
93.445 - if (file == NULL)
93.446 - {
93.447 - printf("Could not open file for segment.\n");
93.448 - return 1;
93.449 - }
93.450 -
93.451 - err = segment->fill(file);
93.452 -
93.453 - if (err)
93.454 - {
93.455 - printf("Could not fill segment from file.\n");
93.456 - return 1;
93.457 - }
93.458 - }
93.459 - else
93.460 - {
93.461 - err = segment->allocate();
93.462 -
93.463 - if (err)
93.464 - {
93.465 - printf("Could not allocate segment.\n");
93.466 - return 1;
93.467 - }
93.468 - }
93.469 - }
93.470 + ExplicitSegment program_stack(Utcb_area_start - initial_stack_size * 2, initial_stack_size, L4_FPAGE_RW);
93.471 + Payload *program_payload;
93.472
93.473 - /* Start the pager. */
93.474 -
93.475 - ipc_server_config_type config;
93.476 - pthread_t pager_thread;
93.477 - pthread_attr_t attr;
93.478 -
93.479 - pthread_attr_init(&attr);
93.480 - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
93.481 -
93.482 - init_pager(&config);
93.483 -
93.484 - for (unsigned int i = 0; i < payload->segments() + 1; i++)
93.485 + if (exec_get_payload(program_filename, &program_payload, false))
93.486 {
93.487 - Segment *segment = segments[i];
93.488 -
93.489 - if (segment == NULL)
93.490 - continue;
93.491 -
93.492 - exec_pager.add(segment->region());
93.493 - }
93.494 -
93.495 - err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &config);
93.496 -
93.497 - if (err)
93.498 - {
93.499 - printf("Could not start pager thread.\n");
93.500 + printf("Could not initialise program: %s\n", program_filename);
93.501 return 1;
93.502 }
93.503
93.504 - err = start_pager(&config, pager_thread);
93.505 + if (program_stack.allocate(true))
93.506 + {
93.507 + printf("Could not allocate program stack.\n");
93.508 + return 1;
93.509 + }
93.510 +
93.511 + /* Initialise pager regions for the region mapper. */
93.512 +
93.513 + for (unsigned int i = 0; i < rm_payload->segments(); i++)
93.514 + {
93.515 + if (rm_payload->segment(i)->loadable())
93.516 + exec_pager.add(rm_payload->segment(i)->region());
93.517 + }
93.518 +
93.519 + exec_pager.add(rm_stack.region());
93.520 +
93.521 + /* Start the pager in a separate thread. */
93.522 +
93.523 + ipc_server_config_type config;
93.524 +
93.525 + printf("Starting pager thread...\n");
93.526 +
93.527 + err = start_pager(config);
93.528
93.529 if (err)
93.530 {
93.531 @@ -484,12 +146,11 @@
93.532 return 1;
93.533 }
93.534
93.535 - /* Configure the environment for the task, specifying the pager (and exception
93.536 - handler plus region mapper). */
93.537 + /* Configure the environment for the task, reserving two threads. */
93.538
93.539 - Process process;
93.540 + Process process(2);
93.541
93.542 - err = process.configure(config.server);
93.543 + err = process.configure_task();
93.544
93.545 if (err)
93.546 {
93.547 @@ -497,30 +158,168 @@
93.548 return 1;
93.549 }
93.550
93.551 - /* Populate a thread stack with argument and environment details. */
93.552 + /* Configure the environment for the thread, specifying the pager (and
93.553 + exception handler plus region mapper). */
93.554 +
93.555 + err = process.configure_thread(config.server);
93.556 +
93.557 + if (err)
93.558 + {
93.559 + printf("Could not configure thread.\n");
93.560 + return 1;
93.561 + }
93.562 +
93.563 + /* Create an unbound IPC gate for the region mapper. */
93.564 +
93.565 + l4_cap_idx_t ipc_gate = ipc_cap_alloc();
93.566 +
93.567 + if (l4_is_invalid_cap(ipc_gate))
93.568 + {
93.569 + printf("Could not allocate IPC gate capability.\n");
93.570 + return 1;
93.571 + }
93.572 +
93.573 + err = l4_error(l4_factory_create_gate(l4re_env()->factory, ipc_gate, L4_INVALID_CAP, 0));
93.574 +
93.575 + if (err)
93.576 + {
93.577 + printf("Could not create IPC gate.\n");
93.578 + return 1;
93.579 + }
93.580 +
93.581 + /* Define regions employing dataspaces to provide program segments.
93.582 +
93.583 + Define capabilities for mapping, including region dataspace capabilities,
93.584 + the stack dataspace capability, and the server capability.
93.585 +
93.586 + Here, the arrays are sized for the maximum number of regions and
93.587 + capabilities, but in practice only the loadable segments are used, leaving
93.588 + fewer elements utilised. A terminating entry is employed to indicate the
93.589 + limit of utilised elements. */
93.590 +
93.591 + struct exec_region rm_regions[rm_payload->segments() + 2];
93.592 + struct ipc_mapped_cap rm_mapped_caps[rm_payload->segments() + 3];
93.593 + l4_cap_idx_t mapped_cap;
93.594 + unsigned int rm_index = 0;
93.595 +
93.596 + for (unsigned int i = 0; i < program_payload->segments(); i++)
93.597 + {
93.598 + Segment *s = program_payload->segment(i);
93.599
93.600 - Stack st(stack);
93.601 + if (s->loadable())
93.602 + {
93.603 + mapped_cap = process.allocate_cap();
93.604 + rm_regions[rm_index] = s->exec_region();
93.605 + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {mapped_cap, rm_regions[rm_index].ds, L4_CAP_FPAGE_RWS, 0};
93.606 + rm_regions[rm_index].ds = mapped_cap;
93.607 + rm_index++;
93.608 + }
93.609 + }
93.610 +
93.611 + /* Introduce the stack region and capability. */
93.612 +
93.613 + mapped_cap = process.allocate_cap();
93.614 + rm_regions[rm_index] = program_stack.exec_region();
93.615 + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {mapped_cap, program_stack.exec_region().ds, L4_CAP_FPAGE_RWS, 0};
93.616 + rm_regions[rm_index].ds = mapped_cap;
93.617 + rm_index++;
93.618 +
93.619 + /* Terminate the region array. */
93.620 +
93.621 + rm_regions[rm_index] = (struct exec_region) {0, 0, 0, L4_INVALID_CAP};
93.622 +
93.623 + /* Introduce the server capability. */
93.624 +
93.625 + l4_cap_idx_t ipc_gate_cap = process.allocate_cap();
93.626 +
93.627 + printf("Mapping %lx to %lx in task.\n", ipc_gate, ipc_gate_cap);
93.628 +
93.629 + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {ipc_gate_cap, ipc_gate, L4_CAP_FPAGE_RWS, L4_FPAGE_C_OBJ_RIGHTS};
93.630 + rm_index++;
93.631 +
93.632 + /* Terminate the capability array. */
93.633 +
93.634 + rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {0, L4_INVALID_CAP, 0, 0};
93.635 +
93.636 + /* Map these additional capabilities. */
93.637 +
93.638 + printf("Map additional capabilities...\n");
93.639 +
93.640 + process.map_capabilities(rm_mapped_caps, false);
93.641 +
93.642 + /* Define the IPC gate as an initial capability to be acquired by the region
93.643 + mapper via the l4re_env API. The capability index is assigned above when
93.644 + mapping the capability and encoded in the entry below. */
93.645 +
93.646 + l4re_env_cap_entry_t rm_init_caps[] = {
93.647 + l4re_env_cap_entry_t("server", ipc_gate_cap, L4_CAP_FPAGE_RWS),
93.648 + l4re_env_cap_entry_t()
93.649 + };
93.650
93.651 /* NOTE: Environment vector is currently not defined. */
93.652
93.653 char *envp[] = {NULL};
93.654
93.655 - st.populate(argc - 1, argv + 1, envp);
93.656 + /* Populate a thread stack with argument and environment details for the
93.657 + region mapper, plus the initial server capability and region details. */
93.658
93.659 - /* Start the new thread in the given stack. */
93.660 + printf("Populating region mapper stack...\n");
93.661 +
93.662 + Stack rm_st(rm_stack);
93.663
93.664 - printf("Run thread...\n");
93.665 + rm_st.set_init_caps(rm_init_caps);
93.666 + rm_st.set_regions(rm_regions);
93.667 + rm_st.populate(1, argv + 1, envp);
93.668
93.669 - err = process.thread_start(program_start, st);
93.670 + /* Start the region mapper thread in the appropriate stack. */
93.671 +
93.672 + printf("Run region mapper thread...\n");
93.673 +
93.674 + err = process.thread_start(rm_payload->entry_point(), rm_st);
93.675
93.676 if (err)
93.677 {
93.678 - printf("Could not run thread.\n");
93.679 + printf("Could not run thread for region mapper.\n");
93.680 + return 1;
93.681 + }
93.682 +
93.683 + /* Configure the environment for the thread, specifying the pager (and
93.684 + exception handler plus region mapper). */
93.685 +
93.686 + err = process.configure_thread(ipc_gate, ipc_gate_cap);
93.687 +
93.688 + if (err)
93.689 + {
93.690 + printf("Could not configure task.\n");
93.691 + return 1;
93.692 + }
93.693 +
93.694 + /* Populate a thread stack with argument and environment details for the
93.695 + actual program. The server capability should be assigned to the region
93.696 + mapper capability slot already. */
93.697 +
93.698 + printf("Populating program stack...\n");
93.699 +
93.700 + Stack program_st(program_stack);
93.701 +
93.702 + program_st.populate(argc - 2, argv + 2, envp);
93.703 +
93.704 + /* Start the program thread in the appropriate stack. */
93.705 +
93.706 + printf("Run program thread...\n");
93.707 +
93.708 + err = process.thread_start(program_payload->entry_point(), program_st);
93.709 +
93.710 + if (err)
93.711 + {
93.712 + printf("Could not run thread for program.\n");
93.713 return 1;
93.714 }
93.715
93.716 printf("Finished.\n");
93.717 - while (1);
93.718 +
93.719 + while (1)
93.720 + l4_sleep_forever();
93.721
93.722 return 0;
93.723 }
94.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
94.2 +++ b/tests/dstest_file_mapping.cc Wed Aug 10 00:25:44 2022 +0200
94.3 @@ -0,0 +1,117 @@
94.4 +/*
94.5 + * Test dataspace operations.
94.6 + *
94.7 + * Copyright (C) 2020, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
94.8 + *
94.9 + * This program is free software; you can redistribute it and/or
94.10 + * modify it under the terms of the GNU General Public License as
94.11 + * published by the Free Software Foundation; either version 2 of
94.12 + * the License, or (at your option) any later version.
94.13 + *
94.14 + * This program is distributed in the hope that it will be useful,
94.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
94.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
94.17 + * GNU General Public License for more details.
94.18 + *
94.19 + * You should have received a copy of the GNU General Public License
94.20 + * along with this program; if not, write to the Free Software
94.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
94.22 + * Boston, MA 02110-1301, USA
94.23 + */
94.24 +
94.25 +#include <l4/re/env.h>
94.26 +#include <l4/sys/err.h>
94.27 +
94.28 +#include <systypes/fcntl.h>
94.29 +
94.30 +#include <stdio.h>
94.31 +#include <string.h>
94.32 +#include <stdlib.h>
94.33 +
94.34 +#include <fsclient/file.h>
94.35 +#include <mem/memory_utils.h>
94.36 +
94.37 +#include "dataspace_client.h"
94.38 +
94.39 +
94.40 +
94.41 +int main(int argc, char *argv[])
94.42 +{
94.43 + if (argc < 4)
94.44 + {
94.45 + printf("Need filename, step and sample size.\n");
94.46 + return 1;
94.47 + }
94.48 +
94.49 + /* Obtain filename and access parameters. */
94.50 +
94.51 + char *filename = argv[1];
94.52 + unsigned long step = atoi(argv[2]);
94.53 + unsigned long sample = atoi(argv[3]);
94.54 +
94.55 + /* Allocate a buffer for sampling from the file. */
94.56 +
94.57 + char buf[sample + 1];
94.58 +
94.59 + /* Obtain access to the filesystem. */
94.60 +
94.61 + l4_cap_idx_t server = l4re_env_get_cap("server");
94.62 +
94.63 + /* Invoke the open method to receive the file reference. */
94.64 +
94.65 + file_t file;
94.66 + long err = file_open(&file, filename, O_RDWR, server);
94.67 +
94.68 + if (err)
94.69 + {
94.70 + printf("Could not obtain file: %s\n", l4sys_errtostr(err));
94.71 + return 1;
94.72 + }
94.73 +
94.74 + /* A region of the file is mapped but not attached. */
94.75 +
94.76 + err = file_mmap_only(&file, 0, page(10), 0, 0);
94.77 +
94.78 + if (err)
94.79 + {
94.80 + printf("Could not map file region: %s\n", l4sys_errtostr(err));
94.81 + return 1;
94.82 + }
94.83 +
94.84 + /* Fix up the file data structure manually. */
94.85 +
94.86 + file.memory = (char *) 0x2000000;
94.87 +
94.88 + /* Explicitly map the file into this address space, without region mapper
94.89 + usage. The receive window base must be a multiple of its size. */
94.90 +
94.91 + client_Dataspace dataspace(file.ref);
94.92 + l4_snd_fpage_t region = {0, l4_fpage((l4_addr_t) file.memory, L4_PAGESHIFT + 4, 0)};
94.93 +
94.94 + printf("region = {%lx, {%lx, %d}}\n", region.snd_base, l4_fpage_memaddr(region.fpage), l4_fpage_size(region.fpage));
94.95 +
94.96 + err = dataspace.map(0, 0, L4_FPAGE_RO, ®ion);
94.97 +
94.98 + if (err)
94.99 + {
94.100 + printf("Could not invoke map successfully: %s\n", l4sys_errtostr(err));
94.101 + return 1;
94.102 + }
94.103 +
94.104 + for (unsigned long offset = 0; offset < file_populated_span(&file); offset += step)
94.105 + {
94.106 + unsigned long remaining = file_populated_span(&file) - offset;
94.107 + unsigned long sample_remaining = remaining < sample ? remaining : sample;
94.108 +
94.109 + printf("%ld bytes from %p...\n", sample_remaining, (file.memory + offset));
94.110 + strncpy(buf, (file.memory + offset), sample_remaining);
94.111 + buf[sample_remaining] = '\0';
94.112 + printf("%s\n", buf);
94.113 + }
94.114 +
94.115 + printf("File shown.\n");
94.116 +
94.117 + return 0;
94.118 +}
94.119 +
94.120 +// vim: tabstop=2 expandtab shiftwidth=2
95.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
95.2 +++ b/tests/dstest_file_remove.cc Wed Aug 10 00:25:44 2022 +0200
95.3 @@ -0,0 +1,146 @@
95.4 +/*
95.5 + * Test removal operations.
95.6 + *
95.7 + * Copyright (C) 2020, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
95.8 + *
95.9 + * This program is free software; you can redistribute it and/or
95.10 + * modify it under the terms of the GNU General Public License as
95.11 + * published by the Free Software Foundation; either version 2 of
95.12 + * the License, or (at your option) any later version.
95.13 + *
95.14 + * This program is distributed in the hope that it will be useful,
95.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
95.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
95.17 + * GNU General Public License for more details.
95.18 + *
95.19 + * You should have received a copy of the GNU General Public License
95.20 + * along with this program; if not, write to the Free Software
95.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
95.22 + * Boston, MA 02110-1301, USA
95.23 + */
95.24 +
95.25 +#include <l4/re/env.h>
95.26 +#include <l4/sys/err.h>
95.27 +
95.28 +#include <stdio.h>
95.29 +#include <string.h>
95.30 +#include <stdlib.h>
95.31 +
95.32 +#include <fsclient/client.h>
95.33 +#include <systypes/fcntl.h>
95.34 +
95.35 +
95.36 +
95.37 +static void read_from_file(file_t *file)
95.38 +{
95.39 + char buf[20];
95.40 + offset_t nread;
95.41 +
95.42 + client_seek(file, 0, SEEK_SET);
95.43 +
95.44 + printf("Reading...\n");
95.45 +
95.46 + nread = client_read(file, buf, 20);
95.47 +
95.48 + printf("Read %ld bytes...\n", nread);
95.49 + fwrite(buf, sizeof(char), nread, stdout);
95.50 + fputs("\n", stdout);
95.51 +}
95.52 +
95.53 +static void write_to_file(file_t *file, const char *buf)
95.54 +{
95.55 + offset_t nwritten;
95.56 +
95.57 + client_seek(file, 0, SEEK_SET);
95.58 +
95.59 + printf("Writing...\n");
95.60 +
95.61 + nwritten = client_write(file, buf, strlen(buf));
95.62 +
95.63 + printf("Wrote %ld bytes: ", nwritten);
95.64 + fwrite(buf, sizeof(char), nwritten, stdout);
95.65 + fputs("\n", stdout);
95.66 +}
95.67 +
95.68 +int main(int argc, char *argv[])
95.69 +{
95.70 + if (argc < 2)
95.71 + {
95.72 + printf("Need a file to remove.\n");
95.73 + return 1;
95.74 + }
95.75 +
95.76 + char *filename = argv[1];
95.77 +
95.78 + printf("Creating %s...\n", filename);
95.79 +
95.80 + file_t *file = client_open(filename, O_WRONLY | O_CREAT);
95.81 +
95.82 + write_to_file(file, "An existing file.");
95.83 +
95.84 + client_close(file);
95.85 +
95.86 + printf("Opening %s...\n", filename);
95.87 +
95.88 + file = client_open(filename, O_RDONLY);
95.89 +
95.90 + if (file == NULL)
95.91 + {
95.92 + printf("Could not open file: %s\n", filename);
95.93 + return 1;
95.94 + }
95.95 +
95.96 + /* Read from the file, then remove the file, then read again. */
95.97 +
95.98 + read_from_file(file);
95.99 +
95.100 + printf("Removing...\n");
95.101 +
95.102 + long err = client_remove(filename);
95.103 +
95.104 + if (err)
95.105 + {
95.106 + printf("Could not remove file: %s\n", filename);
95.107 + return 1;
95.108 + }
95.109 +
95.110 + printf("Reading again...\n");
95.111 +
95.112 + read_from_file(file);
95.113 +
95.114 + /* Open the file again. */
95.115 +
95.116 + file_t *file_new = client_open(filename, O_RDONLY);
95.117 +
95.118 + if (file_new != NULL)
95.119 + {
95.120 + printf("File should be absent: %s\n", filename);
95.121 + return 1;
95.122 + }
95.123 +
95.124 + file_new = client_open(filename, O_RDWR | O_CREAT);
95.125 +
95.126 + if (file_new == NULL)
95.127 + {
95.128 + printf("File should be present: %s\n", filename);
95.129 + return 1;
95.130 + }
95.131 +
95.132 + write_to_file(file_new, "New file!");
95.133 +
95.134 + /* Read from the initial file and new file. */
95.135 +
95.136 + read_from_file(file);
95.137 + read_from_file(file_new);
95.138 +
95.139 + /* Close the files. */
95.140 +
95.141 + client_close(file);
95.142 + client_close(file_new);
95.143 +
95.144 + printf("End of tests.\n");
95.145 +
95.146 + return 0;
95.147 +}
95.148 +
95.149 +// vim: tabstop=2 expandtab shiftwidth=2
96.1 --- a/tests/dstest_host_client.cc Sun Jun 12 17:10:30 2022 +0200
96.2 +++ b/tests/dstest_host_client.cc Wed Aug 10 00:25:44 2022 +0200
96.3 @@ -1,7 +1,7 @@
96.4 /*
96.5 * Test dataspace operations.
96.6 *
96.7 - * Copyright (C) 2020, 2021 Paul Boddie <paul@boddie.org.uk>
96.8 + * Copyright (C) 2020, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
96.9 *
96.10 * This program is free software; you can redistribute it and/or
96.11 * modify it under the terms of the GNU General Public License as
96.12 @@ -68,7 +68,7 @@
96.13
96.14 /* A region of the file is mapped. */
96.15
96.16 - err = file_mmap(&file, 0, page(10));
96.17 + err = file_mmap(&file, 0, page(10), 0, 0, file_region_flags(file.flags));
96.18
96.19 if (err)
96.20 {
97.1 --- a/tests/dstest_test_client.cc Sun Jun 12 17:10:30 2022 +0200
97.2 +++ b/tests/dstest_test_client.cc Wed Aug 10 00:25:44 2022 +0200
97.3 @@ -1,7 +1,7 @@
97.4 /*
97.5 * Test dataspace operations.
97.6 *
97.7 - * Copyright (C) 2020, 2021 Paul Boddie <paul@boddie.org.uk>
97.8 + * Copyright (C) 2020, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
97.9 *
97.10 * This program is free software; you can redistribute it and/or
97.11 * modify it under the terms of the GNU General Public License as
97.12 @@ -77,7 +77,7 @@
97.13
97.14 /* A region of the file is mapped. */
97.15
97.16 - err = file_mmap(&file, page(start_page), page(MAP_PAGES));
97.17 + err = file_mmap(&file, page(start_page), page(MAP_PAGES), 0, 0, file_region_flags(file.flags));
97.18
97.19 if (err)
97.20 {