1.1 --- a/libexec/lib/src/process_creator.cc Sat Feb 18 22:48:39 2023 +0100
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,324 +0,0 @@
1.4 -/*
1.5 - * Support for executing code in new tasks and threads.
1.6 - *
1.7 - * Copyright (C) 2022, 2023 Paul Boddie <paul@boddie.org.uk>
1.8 - *
1.9 - * This program is free software; you can redistribute it and/or
1.10 - * modify it under the terms of the GNU General Public License as
1.11 - * published by the Free Software Foundation; either version 2 of
1.12 - * the License, or (at your option) any later version.
1.13 - *
1.14 - * This program is distributed in the hope that it will be useful,
1.15 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 - * GNU General Public License for more details.
1.18 - *
1.19 - * You should have received a copy of the GNU General Public License
1.20 - * along with this program; if not, write to the Free Software
1.21 - * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 - * Boston, MA 02110-1301, USA
1.23 - */
1.24 -
1.25 -#include <l4/re/env.h>
1.26 -
1.27 -#include <ipc/cap_alloc.h>
1.28 -#include <ipc/map.h>
1.29 -
1.30 -#include <stdio.h>
1.31 -
1.32 -#include <pthread-l4.h>
1.33 -#include <pthread.h>
1.34 -
1.35 -#include "parent_pager_object_server.h"
1.36 -#include "process_creator.h"
1.37 -
1.38 -
1.39 -
1.40 -/* Process stack configuration. */
1.41 -
1.42 -static const offset_t initial_stack_size = 16 * L4_PAGESIZE;
1.43 -
1.44 -
1.45 -
1.46 -/* Initialise the process creator with the details of a region mapper. */
1.47 -
1.48 -ProcessCreator::ProcessCreator(const char *rm_filename)
1.49 -: _rm_filename(rm_filename),
1.50 - _exec_pager(0, 10 * L4_PAGESIZE),
1.51 - _rm_stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW),
1.52 - _program_stack(Utcb_area_start - initial_stack_size * 2, initial_stack_size, L4_FPAGE_RW)
1.53 -{
1.54 -}
1.55 -
1.56 -/* Start the system pager in a separate thread. */
1.57 -
1.58 -long ProcessCreator::start_pager()
1.59 -{
1.60 - pthread_t pager_thread;
1.61 - pthread_attr_t attr;
1.62 -
1.63 - pthread_attr_init(&attr);
1.64 - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1.65 -
1.66 - ipc_server_init_for(&_config, ParentPagerObject, &_exec_pager);
1.67 -
1.68 - long err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &_config);
1.69 -
1.70 - if (err)
1.71 - return err;
1.72 -
1.73 - return ipc_server_start_config_thread(&_config, pthread_l4_cap(pager_thread));
1.74 -}
1.75 -
1.76 -/* Initialise the memory segments of the region mapper. These are mapped into
1.77 - this task so that we may access them, allowing the external pager in this
1.78 - task to use them. */
1.79 -
1.80 -long ProcessCreator::init_region_mapper()
1.81 -{
1.82 - long err = exec_get_payload(_rm_filename, &_rm_payload, true);
1.83 -
1.84 - if (err)
1.85 - return err;
1.86 -
1.87 - return _rm_stack.allocate(true);
1.88 -}
1.89 -
1.90 -/* Initialise the memory segments of the actual program. These are not mapped
1.91 - into this task, instead being accessed by the region mapper in the new
1.92 - task. */
1.93 -
1.94 -long ProcessCreator::init_program(file_t *file)
1.95 -{
1.96 - long err = exec_get_payload_file(file, &_program_payload, false);
1.97 -
1.98 - if (err)
1.99 - return err;
1.100 -
1.101 - return _program_stack.allocate(true);
1.102 -}
1.103 -
1.104 -/* Initialise an external system-level pager serving the region mapper in a
1.105 - created task. The allocated regions requested by the region mapper are
1.106 - constrained to an area of memory that must not overlap with the area reserved
1.107 - for the program being run. */
1.108 -
1.109 -long ProcessCreator::init_external_pager()
1.110 -{
1.111 - /* Initialise pager regions for the region mapper. */
1.112 -
1.113 - for (unsigned int i = 0; i < _rm_payload->segments(); i++)
1.114 - {
1.115 - if (_rm_payload->segment(i)->loadable())
1.116 - _exec_pager.add(_rm_payload->segment(i)->region());
1.117 - }
1.118 -
1.119 - /* Include the region mapper's stack region. */
1.120 -
1.121 - _exec_pager.add(_rm_stack.region());
1.122 -
1.123 - /* Start the pager in a separate thread. */
1.124 -
1.125 - return start_pager();
1.126 -}
1.127 -
1.128 -/* Configure the environment for the task. */
1.129 -
1.130 -long ProcessCreator::configure_task()
1.131 -{
1.132 - long err = _process.configure_task();
1.133 -
1.134 - if (err)
1.135 - return err;
1.136 -
1.137 - return _process.set_parent(_config.server);
1.138 -}
1.139 -
1.140 -/* Create an unbound IPC gate for the region mapper and allocate it in the
1.141 - created process. */
1.142 -
1.143 -long ProcessCreator::create_ipc_gate()
1.144 -{
1.145 - _ipc_gate_cap = _process.allocate_cap();
1.146 - _ipc_gate = ipc_cap_alloc();
1.147 -
1.148 - if (l4_is_invalid_cap(_ipc_gate))
1.149 - return -L4_ENOMEM;
1.150 -
1.151 - return l4_error(l4_factory_create_gate(l4re_env()->factory, _ipc_gate, L4_INVALID_CAP, 0));
1.152 -}
1.153 -
1.154 -/* Initialise and assign a region in a list to the created process. */
1.155 -
1.156 -void ProcessCreator::init_region(struct exec_region *regions,
1.157 - struct ipc_mapped_cap *mapped_caps,
1.158 - struct exec_region &r, unsigned int &index)
1.159 -{
1.160 - l4_cap_idx_t mapped_cap = _process.allocate_cap();
1.161 -
1.162 - mapped_caps[index] = (struct ipc_mapped_cap) {mapped_cap, r.ds, L4_CAP_FPAGE_RWS, 0};
1.163 -
1.164 - /* Change the region definition to use the allocated capability in the created
1.165 - process. */
1.166 -
1.167 - regions[index] = r;
1.168 - regions[index].ds = mapped_cap;
1.169 - index++;
1.170 -}
1.171 -
1.172 -/* Initialise the region mapper with details of the payload program regions
1.173 - and of the associated capabilities, configure the region mapper thread,
1.174 - populate its stack, and start the thread. */
1.175 -
1.176 -long ProcessCreator::start_region_mapper()
1.177 -{
1.178 - /* Define regions employing dataspaces to provide program segments. */
1.179 -
1.180 - struct exec_region rm_regions[_rm_payload->segments() + 2];
1.181 -
1.182 - /* Define capabilities for mapping, including region dataspace capabilities,
1.183 - the stack dataspace capability, and the server capability. */
1.184 -
1.185 - struct ipc_mapped_cap rm_mapped_caps[_rm_payload->segments() + 3];
1.186 -
1.187 - /* Here, the arrays are sized for the maximum number of regions and
1.188 - capabilities, but in practice only the loadable segments are used, leaving
1.189 - fewer elements utilised. A terminating entry is employed to indicate the
1.190 - limit of utilised elements. */
1.191 -
1.192 - unsigned int rm_index = 0;
1.193 -
1.194 - for (unsigned int i = 0; i < _program_payload->segments(); i++)
1.195 - {
1.196 - Segment *s = _program_payload->segment(i);
1.197 -
1.198 - if (s->loadable())
1.199 - init_region(rm_regions, rm_mapped_caps, s->exec_region(), rm_index);
1.200 - }
1.201 -
1.202 - /* Introduce the stack region and capability. */
1.203 -
1.204 - init_region(rm_regions, rm_mapped_caps, _program_stack.exec_region(), rm_index);
1.205 -
1.206 - /* Terminate the region array. */
1.207 -
1.208 - rm_regions[rm_index] = (struct exec_region) {0, 0, 0, L4_INVALID_CAP};
1.209 -
1.210 - /* Introduce the server capability and terminate the capability array. */
1.211 -
1.212 - rm_mapped_caps[rm_index++] = (struct ipc_mapped_cap) {_ipc_gate_cap, _ipc_gate, L4_CAP_FPAGE_RWS, L4_FPAGE_C_OBJ_RIGHTS};
1.213 - rm_mapped_caps[rm_index] = (struct ipc_mapped_cap) {0, L4_INVALID_CAP, 0, 0};
1.214 -
1.215 - /* Map these additional capabilities. */
1.216 -
1.217 - _process.map_capabilities(rm_mapped_caps, false);
1.218 -
1.219 - /* Define the IPC gate as an initial capability to be acquired by the region
1.220 - mapper via the l4re_env API. The capability index is assigned above when
1.221 - mapping the capability and encoded in the entry below. */
1.222 -
1.223 - l4re_env_cap_entry_t rm_init_caps[] = {
1.224 - l4re_env_cap_entry_t("server", _ipc_gate_cap, L4_CAP_FPAGE_RWS),
1.225 - l4re_env_cap_entry_t()
1.226 - };
1.227 -
1.228 - /* NOTE: Environment vector is currently not defined. */
1.229 -
1.230 - const char *envp[] = {NULL};
1.231 -
1.232 - /* Configure the environment for the thread, specifying the pager (and
1.233 - exception handler plus region mapper). */
1.234 -
1.235 - long err = _process.configure_thread(_config.server);
1.236 -
1.237 - if (err)
1.238 - return err;
1.239 -
1.240 - /* Populate a thread stack with argument and environment details for the
1.241 - region mapper, plus the initial server capability and region details. */
1.242 -
1.243 - const char *argv[] = {_rm_filename};
1.244 - Stack rm_st(_rm_stack);
1.245 -
1.246 - rm_st.set_init_caps(rm_init_caps);
1.247 - rm_st.set_regions(rm_regions);
1.248 - rm_st.populate(1, argv, envp);
1.249 -
1.250 - /* Start the region mapper thread in the appropriate stack. */
1.251 -
1.252 - return _process.thread_start(_rm_payload->entry_point(), rm_st);
1.253 -}
1.254 -
1.255 -/* Configure a thread for a program, populate its stack, and start the
1.256 - thread. */
1.257 -
1.258 -long ProcessCreator::start_program(int argc, const char *argv[])
1.259 -{
1.260 - /* NOTE: Environment vector is currently not defined. */
1.261 -
1.262 - const char *envp[] = {NULL};
1.263 -
1.264 - /* Configure the environment for the thread, specifying the pager (and
1.265 - exception handler plus region mapper). */
1.266 -
1.267 - long err = _process.configure_thread(_ipc_gate, _ipc_gate_cap);
1.268 -
1.269 - if (err)
1.270 - return err;
1.271 -
1.272 - /* Populate a thread stack with argument and environment details for the
1.273 - actual program. The server capability should be assigned to the region
1.274 - mapper capability slot already. */
1.275 -
1.276 - Stack program_st(_program_stack);
1.277 -
1.278 - program_st.populate(argc, argv, envp);
1.279 -
1.280 - /* Start the program thread in the appropriate stack. */
1.281 -
1.282 - return _process.thread_start(_program_payload->entry_point(), program_st);
1.283 -}
1.284 -
1.285 -/* Start a new process for the given payload, providing the indicated program
1.286 - arguments. */
1.287 -
1.288 -long ProcessCreator::start(file_t *file, int argc, const char *argv[])
1.289 -{
1.290 - long err;
1.291 -
1.292 - err = init_region_mapper();
1.293 - if (err)
1.294 - return err;
1.295 -
1.296 - err = init_program(file);
1.297 - if (err)
1.298 - return err;
1.299 -
1.300 - err = init_external_pager();
1.301 - if (err)
1.302 - return err;
1.303 -
1.304 - err = configure_task();
1.305 - if (err)
1.306 - return err;
1.307 -
1.308 - err = create_ipc_gate();
1.309 - if (err)
1.310 - return err;
1.311 -
1.312 - err = start_region_mapper();
1.313 - if (err)
1.314 - return err;
1.315 -
1.316 - return start_program(argc, argv);
1.317 -}
1.318 -
1.319 -/* Set the given notifier on the system-level pager for a process. */
1.320 -
1.321 -void ProcessCreator::set_notifier(Notifier *notifier)
1.322 -{
1.323 - _exec_pager.set_notifier(notifier);
1.324 -}
1.325 -
1.326 -/* vim: tabstop=2 expandtab shiftwidth=2
1.327 -*/