# HG changeset patch # User Paul Boddie # Date 1652215155 -7200 # Node ID 63050823f95b8c17bd606ae3adee08accbf6a347 # Parent 6589577799e69a7b82420db0166b5e61dfe3d965 Moved various abstractions and functions to a new libexec library and to libipc. diff -r 6589577799e6 -r 63050823f95b libexec/Control --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/Control Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,3 @@ +requires: libstdc++ libc libmem libipc libsystypes libfsclient +provides: libexec +maintainer: paul@boddie.org.uk diff -r 6589577799e6 -r 63050823f95b libexec/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/Makefile Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,4 @@ +PKGDIR ?= . +L4DIR ?= $(PKGDIR)/../../.. + +include $(L4DIR)/mk/subdir.mk diff -r 6589577799e6 -r 63050823f95b libexec/include/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/include/Makefile Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,7 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../../.. + +PKGNAME = libexec +CONTRIB_HEADERS = 1 + +include $(L4DIR)/mk/include.mk diff -r 6589577799e6 -r 63050823f95b libexec/include/exec/mapped_region.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/include/exec/mapped_region.h Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,51 @@ +/* + * Mapped memory region support. + * + * Copyright (C) 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include + + + +/* A mapped region abstraction. */ + +class MappedRegion +{ +public: + l4_addr_t start; + unsigned int log2size; + l4_umword_t flags; + l4_addr_t map_start; + + explicit MappedRegion() + : start(0), log2size(0), flags(0), map_start(0) + { + } + + explicit MappedRegion(l4_addr_t start, unsigned int log2size, + l4_umword_t flags, l4_addr_t map_start) + : start(start), log2size(log2size), flags(flags), map_start(map_start) + { + } +}; + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 6589577799e6 -r 63050823f95b libexec/include/exec/process.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/include/exec/process.h Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,99 @@ +/* + * Support for initialising programs in new tasks and threads. + * + * Copyright (C) 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + + + +/* UTCB properties. + See: moe/server/src/loader.cc */ + +enum exec_utcb +{ + Default_max_threads = 16, +#ifdef ARCH_mips + Utcb_area_start = 0x73000000, +#else + Utcb_area_start = 0xb3000000, +#endif +}; + + + +/* Capability index definitions. */ + +enum exec_task_caps +{ + L4_EXEC_PAGER_CAP = 0x10 << L4_CAP_SHIFT, + L4_EXEC_RM_CAP = 0x11 << L4_CAP_SHIFT, + L4_EXEC_MA_CAP = 0x12 << L4_CAP_SHIFT, + L4_EXEC_KIP_CAP = 0x14 << L4_CAP_SHIFT, +}; + +/* The default first free capability index must follow those above. */ + +enum exec_task_cap_indexes +{ + L4_EXEC_FIRST_FREE_CAP_INDEX = 0x15, +}; + + + +/* A process abstraction. */ + +class Process +{ +protected: + l4_cap_idx_t _task = L4_INVALID_CAP; + + /* UTCB details. */ + + l4_addr_t _utcb_start; + + /* Common environment details. */ + + l4re_aux_t _aux; + l4re_env_t _env; + + /* Task and thread initialisation. */ + + long create_task(); + + long create_thread(l4_cap_idx_t *thread); + +public: + explicit Process(); + + long configure(l4_cap_idx_t server); + + long thread_start(l4_addr_t program_start, Stack &st); +}; + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 6589577799e6 -r 63050823f95b libexec/include/exec/segment.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/include/exec/segment.h Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,81 @@ +/* + * Program memory segment support. + * + * Copyright (C) 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + +#include + +#include + + + +/* Program segment abstraction. */ + +class Segment +{ +protected: + MappedRegion _region; + +public: + /* Allocated memory. */ + + char *buf; + l4re_ds_t ds; + + /* Segment base and corresponding region base. */ + + l4_addr_t base, region_base; + + /* Segment size and corresponding region size. */ + + offset_t size, region_size; + + /* Offset of segment content within the region. */ + + offset_t region_offset; + + /* Access flags. */ + + l4re_rm_flags_t flags; + + /* File access details. */ + + offset_t file_offset, file_contents; + + explicit Segment(offset_t base, offset_t size, l4re_rm_flags_t flags, + offset_t file_offset = 0, offset_t file_contents = 0); + + long allocate(); + + long fill(file_t *file); + + MappedRegion ®ion(); + + l4_addr_t region_address(char *address); + + l4_addr_t region_address(l4_addr_t address); +}; + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 6589577799e6 -r 63050823f95b libexec/include/exec/stack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/include/exec/stack.h Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,106 @@ +/* + * Stack support for new tasks and threads. + * + * Copyright (C) 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + +#include + + + +/* A stack abstraction. */ + +class Stack +{ +protected: + + /* Auxiliary vector key-value pair. */ + + struct auxv_entry + { + l4_umword_t key, value; + }; + + /* Program segment holding the stack contents. */ + + Segment &_segment; + + /* Next element pointer. */ + + l4_umword_t *_element; + + /* Stack section properties. */ + + l4_addr_t _caps; + char *_arg_top, *_env_top; + char **_argv; + char *_auxv_end; + int _env_entries; + + /* L4Re auxiliary and environment regions. */ + + l4re_aux_t *_aux; + l4re_env_t *_env; + + /* Stack pointer start address. */ + + l4_addr_t _start; + + /* Internal stack population methods. */ + + void push_cap_entries(l4re_env_cap_entry_t *entries); + + void push_string(char *s); + + void push_env(char *envp[]); + + void push_args(int argc, char *argv[]); + + void push_l4re_aux(); + + void push_l4re_env(); + + void push_auxv(); + + offset_t write_address(char *arg, char **addr, char *s); + + void push_envp(char *envp[]); + + void push_argv(int argc, char *argv[]); + + l4_addr_t align_stack(); + +public: + explicit Stack(Segment &segment); + + void set_l4re_aux(l4re_aux_t *aux); + + void set_l4re_env(l4re_env_t *env); + + void populate(int argc, char *argv[], char *envp[]); + + l4_addr_t start_address(); +}; + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 6589577799e6 -r 63050823f95b libexec/lib/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/lib/Makefile Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,4 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../../.. + +include $(L4DIR)/mk/subdir.mk diff -r 6589577799e6 -r 63050823f95b libexec/lib/src/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/lib/src/Makefile Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,12 @@ +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR)/../../.. + +TARGET = libexec.a libexec.so +PC_FILENAME = libexec +SRC_CC = process.cc segment.cc stack.cc +REQUIRES_LIBS = l4re_c-util libmem libipc libstdc++ libsystypes libfsclient + +PRIVATE_INCDIR += $(PKGDIR)/include/exec +CONTRIB_INCDIR = libexec + +include $(L4DIR)/mk/lib.mk diff -r 6589577799e6 -r 63050823f95b libexec/lib/src/process.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/lib/src/process.cc Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,193 @@ +/* + * Support for initialising programs in new tasks and threads. + * + * Copyright (C) 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include +#include +#include +#include + + + +/* Obtain a flexpage defining the UTCB area location and size in a new task. */ + +static l4_fpage_t get_utcb_fpage() +{ + /* UTCB location and size. */ + + int utcb_log2size = page_order(Default_max_threads * L4_UTCB_OFFSET); + + /* Round up to at least one page. */ + + if (utcb_log2size < L4_PAGESHIFT) + utcb_log2size = L4_PAGESHIFT; + + return l4_fpage(Utcb_area_start, utcb_log2size, 0); +} + + + +/* Initialise a new process, this being an abstraction for a new task with some + threads. */ + +Process::Process() +{ + /* Obtain UTCB area details for the task. */ + + l4_fpage_t utcb_fpage = get_utcb_fpage(); + + _utcb_start = l4_fpage_memaddr(utcb_fpage); + + /* Populate the common initial environment for the threads. */ + + _env.factory = L4_BASE_FACTORY_CAP; + _env.main_thread = L4_BASE_THREAD_CAP; + _env.log = L4_BASE_LOG_CAP; + _env.scheduler = L4_BASE_SCHEDULER_CAP; + _env.rm = L4_EXEC_RM_CAP; + _env.mem_alloc = L4_EXEC_MA_CAP; + _env.first_free_cap = L4_EXEC_FIRST_FREE_CAP_INDEX; + _env.utcb_area = utcb_fpage; + _env.first_free_utcb = l4_fpage_memaddr(utcb_fpage) + L4_UTCB_OFFSET; + + /* Populate auxiliary information. */ + + _aux.kip_ds = L4_EXEC_KIP_CAP; + _aux.dbg_lvl = 0; + _aux.ldr_flags = 0; +} + +/* Task and thread initialisation. */ + +long Process::create_task() +{ + _task = ipc_cap_alloc(); + + if (l4_is_invalid_cap(_task)) + return -L4_ENOMEM; + + return l4_error(l4_factory_create_task(l4re_env()->factory, _task, _env.utcb_area)); +} + +long Process::create_thread(l4_cap_idx_t *thread) +{ + *thread = ipc_cap_alloc(); + + if (l4_is_invalid_cap(*thread)) + return -L4_ENOMEM; + + return l4_error(l4_factory_create_thread(l4re_env()->factory, *thread)); +} + +/* Configure the task environment. */ + +long Process::configure(l4_cap_idx_t server) +{ + long err = create_task(); + + if (err) + return err; + + /* Map the KIP into the task. */ + + l4_addr_t kip_start = (l4_addr_t) l4re_kip(); + + err = l4_error(l4_task_map(_task, L4RE_THIS_TASK_CAP, + l4_fpage(kip_start, L4_PAGESHIFT, L4_FPAGE_RX), + kip_start)); + + if (err) + return err; + + /* Define capability mappings for the new task. */ + + struct ipc_mapped_cap mapped_caps[] = { + {L4_BASE_TASK_CAP, _task, L4_CAP_FPAGE_RWS}, + {L4_EXEC_PAGER_CAP, server, L4_CAP_FPAGE_RWS}, + {_env.rm, server, L4_CAP_FPAGE_RWS}, + {_env.factory, l4re_env()->factory, L4_CAP_FPAGE_RWS}, + {_env.log, l4re_env()->log, L4_CAP_FPAGE_RWS}, + {_env.scheduler, l4re_env()->scheduler, L4_CAP_FPAGE_RWS}, + {_env.mem_alloc, l4re_env()->mem_alloc, L4_CAP_FPAGE_RWS}, + {0, L4_INVALID_CAP, 0}, + }; + + return ipc_map_capabilities(_task, mapped_caps); +} + +/* Create, initialise and start a thread. */ + +long Process::thread_start(l4_addr_t program_start, Stack &st) +{ + l4_cap_idx_t thread; + long err; + + err = create_thread(&thread); + + if (err) + return err; + + /* Initialise the thread with pager, UTCB and task details. */ + + l4_thread_control_start(); + l4_thread_control_pager(L4_EXEC_PAGER_CAP); + l4_thread_control_exc_handler(L4_EXEC_PAGER_CAP); + l4_thread_control_bind((l4_utcb_t *) _utcb_start, _task); + + err = l4_error(l4_thread_control_commit(thread)); + + if (err) + { + ipc_cap_free(thread); + return err; + } + + /* Map the thread capability to the task. */ + + ipc_map_capability(_task, (struct ipc_mapped_cap) {_env.main_thread, thread, L4_CAP_FPAGE_RWS}); + + /* Populate the initial environment in the thread. */ + + st.set_l4re_aux(&_aux); + st.set_l4re_env(&_env); + + /* Set the start details. */ + + err = l4_error(l4_thread_ex_regs(thread, program_start, st.start_address(), 0)); + + if (err) + return err; + + /* Select a new address for the next thread. */ + + _utcb_start += L4_UTCB_OFFSET; + + /* Start the thread. */ + + l4_sched_param_t sp = l4_sched_param(L4RE_MAIN_THREAD_PRIO); + + return l4_error(l4_scheduler_run_thread(l4re_env()->scheduler, thread, &sp)); +} + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 6589577799e6 -r 63050823f95b libexec/lib/src/segment.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/lib/src/segment.cc Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,92 @@ +/* + * Program memory segment support. + * + * Copyright (C) 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include +#include + +#include +#include + +#include "segment.h" + + + +/* Initialise a memory segment. */ + +Segment::Segment(offset_t base, offset_t size, l4re_rm_flags_t flags, + offset_t file_offset, offset_t file_contents) +: base(base), size(size), flags(flags), file_offset(file_offset), + file_contents(file_contents) +{ + region_base = trunc(base, L4_PAGESIZE); + region_offset = base - region_base; + region_size = round(size, L4_PAGESIZE); +} + +/* Allocate a region for the segment. */ + +long Segment::allocate() +{ + return ipc_allocate_align(size, L4RE_RM_F_SEARCH_ADDR | flags, + L4_PAGESHIFT, (void **) &buf, &ds); +} + +/* Fill a segment region with file content. */ + +long Segment::fill(file_t *file) +{ + if (!file_contents) + return L4_EOK; + + memset(buf, 0, region_size); + client_seek(file, file_offset, SEEK_SET); + offset_t nread = client_read(file, buf + region_offset, file_contents); + + if (nread < file_contents) + return -L4_EIO; + else + return L4_EOK; +} + +/* Define and return the mapped region for the segment. */ + +MappedRegion &Segment::region() +{ + _region = MappedRegion((l4_addr_t) buf, page_order(region_size), flags, region_base); + return _region; +} + +/* Return the mapped address corresponding to the given address. */ + +l4_addr_t Segment::region_address(char *address) +{ + return (l4_addr_t) ((address - buf) + (char *) region_base); +} + +l4_addr_t Segment::region_address(l4_addr_t address) +{ + return (address - (l4_addr_t) buf) + region_base; +} + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 6589577799e6 -r 63050823f95b libexec/lib/src/stack.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/lib/src/stack.cc Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,271 @@ +/* + * Stack support for new tasks and threads. + * + * Copyright (C) 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include + +#include + +#include + +#include +#include + +#include "stack.h" + + + +/* Initialise a stack in a memory segment. */ + +Stack::Stack(Segment &segment) +: _segment(segment) +{ + _element = (l4_umword_t *) (segment.buf + segment.size); + + /* Add a terminator for any additional initial capabilities. */ + + l4re_env_cap_entry_t *entry = (l4re_env_cap_entry_t *) _element; + + *(--entry) = l4re_env_cap_entry_t(); + _element = (l4_umword_t *) entry; +} + +/* Push any additional initial capabilities. */ + +void Stack::push_cap_entries(l4re_env_cap_entry_t *entries) +{ + l4re_env_cap_entry_t *entry = (l4re_env_cap_entry_t *) _element; + + while ((entries != NULL) && (entries->cap != L4_INVALID_CAP)) + *(--entry) = *entries; + + _caps = (l4_addr_t) entry; + _element = (l4_umword_t *) entry; +} + +/* Push environment values in reverse order. */ + +void Stack::push_string(char *s) +{ + char *arg = (char *) _element; + char *arg_last = arg; + + arg -= round(strlen(s) + 1, sizeof(l4_umword_t)); + + memset(arg, 0, arg_last - arg); + memcpy(arg, s, strlen(s)); + + _element = (l4_umword_t *) arg; +} + +/* Push environment values in reverse order. */ + +void Stack::push_env(char *envp[]) +{ + _env_top = (char *) _element; + _env_entries = 0; + + for (; *envp != NULL; envp++, _env_entries++) + push_string(*envp); +} + +/* Push argument values in reverse order. */ + +void Stack::push_args(int argc, char *argv[]) +{ + _arg_top = (char *) _element; + + for (int i = 0; i < argc; i++) + push_string(argv[i]); +} + +/* Loader flags, debugging flags, and the KIP capability index. + See: generate_l4aux in Remote_app_model */ + +void Stack::push_l4re_aux() +{ + _aux = (l4re_aux_t *) _element; + _aux--; + _element = (l4_umword_t *) _aux; +} + +void Stack::push_l4re_env() +{ + _env = (l4re_env_t *) _element; + _env--; + _element = (l4_umword_t *) _env; +} + +/* Set the common auxiliary information. */ + +void Stack::set_l4re_aux(l4re_aux_t *aux) +{ + memcpy(_aux, aux, sizeof(l4re_aux_t)); + + /* Take the binary name from the first program argument. */ + + _aux->binary = (char *) _argv[0]; +} + +/* Set the common environment, introducing the reference to additional + capabilities. */ + +void Stack::set_l4re_env(l4re_env_t *env) +{ + memcpy(_env, env, sizeof(l4re_env_t)); + _env->caps = (l4re_env_cap_entry_t *) (_segment.region_address(_caps)); +} + +/* Push the auxiliary vector. */ + +void Stack::push_auxv() +{ + _auxv_end = (char *) _element; + + struct auxv_entry *auxv_base = (struct auxv_entry *) _element; + + *(--auxv_base) = {AT_NULL, 0}; + + /* L4Re global environment pointer. */ + + *(--auxv_base) = {AT_L4_ENV, _segment.region_address((char *) _env)}; + + /* L4Re auxiliary structure pointer. */ + + *(--auxv_base) = {AT_L4_AUX, _segment.region_address((char *) _aux)}; + + /* Apparently required entries. + NOTE: The user/group identifiers should be obtained from the broader + environment. */ + + *(--auxv_base) = {AT_PAGESZ, L4_PAGESIZE}; + *(--auxv_base) = {AT_UID, 0}; + *(--auxv_base) = {AT_EUID, 0}; + *(--auxv_base) = {AT_GID, 0}; + *(--auxv_base) = {AT_EGID, 0}; + + _element = (l4_umword_t *) auxv_base; +} + +/* Fill the stack in reverse with an address, returning the size of the + value. */ + +offset_t Stack::write_address(char *arg, char **addr, char *s) +{ + offset_t size = round(strlen(s) + 1, sizeof(l4_umword_t)); + + *addr = (char *) _segment.region_address(arg - size); + return size; +} + +/* Populate stack with environment pointers, employing a pointer ordering + that is the reverse of the value ordering. */ + +void Stack::push_envp(char *envp[]) +{ + /* Write the terminating element. */ + + *(--_element) = 0; + + /* Reserve space and fill the stack from the top inwards. */ + + char **ep = (char **) (_element - _env_entries); + char *arg = _env_top; + + for (; *envp != NULL; envp++, ep++) + arg -= write_address(arg, ep, *envp); + + _element -= _env_entries; +} + +/* Populate stack with argument pointers and count, employing a pointer + ordering that is the reverse of the value ordering. */ + +void Stack::push_argv(int argc, char *argv[]) +{ + /* Write the terminating element. */ + + *(--_element) = 0; + + /* Reserve space and fill the stack from the top inwards. */ + + _argv = (char **) (_element - argc); + char *arg = _arg_top; + + for (int i = 0; i < argc; i++) + arg -= write_address(arg, &_argv[i], argv[i]); + + /* Write the count. */ + + _element -= argc; + + *(--_element) = argc; +} + +/* Adjust the stack alignment and return the stack address. */ + +l4_addr_t Stack::align_stack() +{ + char *current = (char *) _element; + char *adjusted = Ldr::adjust_sp(current, NULL); + + if (adjusted != current) + memmove(adjusted, (const void *) current, _auxv_end - current); + + _element = (l4_umword_t *) adjusted; + + return _segment.region_address(adjusted); +} + +/* Populate the stack with arguments and initial environment. */ + +void Stack::populate(int argc, char *argv[], char *envp[]) +{ + /* Populate stack with environment and argument values. */ + + push_env(envp); + push_args(argc, argv); + + /* Push L4Re flags, environment and auxiliary vector. */ + + push_l4re_aux(); + push_l4re_env(); + push_auxv(); + + /* Push environment and argument pointers. */ + + push_envp(envp); + push_argv(argc, argv); + + /* Adjust the stack alignment, setting the start address. */ + + _start = align_stack(); +} + +/* Return the stack pointer start address in the mapped program segment. */ + +l4_addr_t Stack::start_address() +{ + return _start; +} + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 6589577799e6 -r 63050823f95b libipc/include/ipc/map.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/include/ipc/map.h Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,39 @@ +/* + * Capability mapping between tasks. + * + * Copyright (C) 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include + +EXTERN_C_BEGIN + +struct ipc_mapped_cap +{ + l4_umword_t index; + l4_cap_idx_t cap; + unsigned char rights; +}; + +long ipc_map_capability(l4_cap_idx_t task, struct ipc_mapped_cap mapped_cap); + +long ipc_map_capabilities(l4_cap_idx_t task, struct ipc_mapped_cap mapped_caps[]); + +EXTERN_C_END diff -r 6589577799e6 -r 63050823f95b libipc/lib/src/Makefile --- a/libipc/lib/src/Makefile Tue May 10 16:50:21 2022 +0200 +++ b/libipc/lib/src/Makefile Tue May 10 22:39:15 2022 +0200 @@ -3,7 +3,7 @@ TARGET = libipc.a libipc.so PC_FILENAME = libipc -SRC_C = cap_alloc.c direct.c irq.c mem_ipc.c message.c semaphore.c server.c thread.c util_ipc.c +SRC_C = cap_alloc.c direct.c irq.c map.c mem_ipc.c message.c semaphore.c server.c thread.c util_ipc.c REQUIRES_LIBS = l4re_c-util PRIVATE_INCDIR += $(PKGDIR)/include/ipc diff -r 6589577799e6 -r 63050823f95b libipc/lib/src/map.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libipc/lib/src/map.c Tue May 10 22:39:15 2022 +0200 @@ -0,0 +1,52 @@ +/* + * Capability mapping between tasks. + * + * Copyright (C) 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include "map.h" + + + +/* Map a capability to another task. */ + +long ipc_map_capability(l4_cap_idx_t task, struct ipc_mapped_cap mapped_cap) +{ + return l4_error(l4_task_map(task, L4RE_THIS_TASK_CAP, + l4_obj_fpage(mapped_cap.cap, 0, mapped_cap.rights), + l4_map_obj_control(mapped_cap.index, L4_MAP_ITEM_MAP))); +} + +/* Map several capabilities to another task. */ + +long ipc_map_capabilities(l4_cap_idx_t task, struct ipc_mapped_cap mapped_caps[]) +{ + long err = L4_EOK; + + for (int i = 0; l4_is_valid_cap(mapped_caps[i].cap) && !err; i++) + err = ipc_map_capability(task, mapped_caps[i]); + + return err; +} + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 6589577799e6 -r 63050823f95b tests/Control --- a/tests/Control Tue May 10 16:50:21 2022 +0200 +++ b/tests/Control Tue May 10 22:39:15 2022 +0200 @@ -1,3 +1,3 @@ -requires: libstdc++ libc libipc libfsclient libmem libext2fs libext2fs_blockserver libe2access_blockserver fstest_files +requires: libstdc++ libc libexec libipc libfsclient libmem libext2fs libext2fs_blockserver libe2access_blockserver fstest_files provides: fstests maintainer: paul@boddie.org.uk diff -r 6589577799e6 -r 63050823f95b tests/Makefile --- a/tests/Makefile Tue May 10 16:50:21 2022 +0200 +++ b/tests/Makefile Tue May 10 22:39:15 2022 +0200 @@ -71,7 +71,7 @@ PLAIN_SRC_CC_dstest_exec = dstest_exec.cc SRC_CC_dstest_exec = $(PLAIN_SRC_CC_dstest_exec) $(SERVER_INTERFACES_SRC_CC) -REQUIRES_LIBS = l4re_c-util libfsclient libmem libipc libstdc++ libsystypes libe2access_blockserver +REQUIRES_LIBS = l4re_c-util libexec libfsclient libmem libipc libstdc++ libsystypes libe2access_blockserver PRIVATE_INCDIR = $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR) include $(L4DIR)/mk/prog.mk diff -r 6589577799e6 -r 63050823f95b tests/dstest_exec.cc --- a/tests/dstest_exec.cc Tue May 10 16:50:21 2022 +0200 +++ b/tests/dstest_exec.cc Tue May 10 22:39:15 2022 +0200 @@ -22,16 +22,11 @@ #include #include #include -#include -#include -#include #include #include -#include - +#include #include -#include #include #include #include @@ -51,151 +46,6 @@ -/* UTCB properties. - See: moe/server/src/loader.cc */ - -enum ipc_exec_utcb -{ - Default_max_threads = 16, -#ifdef ARCH_mips - Utcb_area_start = 0x73000000, -#else - Utcb_area_start = 0xb3000000, -#endif -}; - -static l4_fpage_t get_utcb_fpage() -{ - /* UTCB location and size. */ - - int utcb_log2size = page_order(Default_max_threads * L4_UTCB_OFFSET); - - /* Round up to at least one page. */ - - if (utcb_log2size < L4_PAGESHIFT) - utcb_log2size = L4_PAGESHIFT; - - return l4_fpage(Utcb_area_start, utcb_log2size, 0); -} - - - -/* Mapped region data structures. */ - -class MappedRegion -{ -public: - l4_addr_t start; - unsigned int log2size; - l4_umword_t flags; - l4_addr_t map_start; - - explicit MappedRegion() - : start(0), log2size(0), flags(0), map_start(0) - { - } - - explicit MappedRegion(l4_addr_t start, unsigned int log2size, - l4_umword_t flags, l4_addr_t map_start) - : start(start), log2size(log2size), flags(flags), map_start(map_start) - { - } -}; - - - -/* Program segment abstraction. */ - -class Segment -{ -protected: - MappedRegion _region; - -public: - /* Allocated memory. */ - - char *buf; - l4re_ds_t ds; - - /* Segment base and corresponding region base. */ - - l4_addr_t base, region_base; - - /* Segment size and corresponding region size. */ - - offset_t size, region_size; - - /* Offset of segment content within the region. */ - - offset_t region_offset; - - /* Access flags. */ - - l4re_rm_flags_t flags; - - /* File access details. */ - - offset_t file_offset, file_contents; - - explicit Segment(offset_t base, offset_t size, l4re_rm_flags_t flags, - offset_t file_offset = 0, offset_t file_contents = 0) - : base(base), size(size), flags(flags), file_offset(file_offset), file_contents(file_contents) - { - region_base = trunc(base, L4_PAGESIZE); - region_offset = base - region_base; - region_size = round(size, L4_PAGESIZE); - } - - long allocate(); - - long fill(file_t *file); - - MappedRegion ®ion(); - - l4_addr_t region_address(char *address); - - l4_addr_t region_address(l4_addr_t address); -}; - -long Segment::allocate() -{ - return ipc_allocate_align(size, L4RE_RM_F_SEARCH_ADDR | flags, - L4_PAGESHIFT, (void **) &buf, &ds); -} - -long Segment::fill(file_t *file) -{ - if (!file_contents) - return L4_EOK; - - memset(buf, 0, region_size); - client_seek(file, file_offset, SEEK_SET); - offset_t nread = client_read(file, buf + region_offset, file_contents); - - if (nread < file_contents) - return -L4_EIO; - else - return L4_EOK; -} - -MappedRegion &Segment::region() -{ - _region = MappedRegion((l4_addr_t) buf, page_order(region_size), flags, region_base); - return _region; -} - -l4_addr_t Segment::region_address(char *address) -{ - return (l4_addr_t) ((address - buf) + (char *) region_base); -} - -l4_addr_t Segment::region_address(l4_addr_t address) -{ - return (address - (l4_addr_t) buf) + region_base; -} - - - /* A simple system pager also acting as a region mapper. */ typedef std::map MappedRegions; @@ -425,465 +275,6 @@ -/* Capability mapping definitions for the new task. */ - -struct mapped_cap -{ - l4_umword_t index; - l4_cap_idx_t cap; - unsigned char rights; -}; - -static long map_capability(l4_cap_idx_t task, struct mapped_cap mapped_cap) -{ - return l4_error(l4_task_map(task, L4RE_THIS_TASK_CAP, - l4_obj_fpage(mapped_cap.cap, 0, mapped_cap.rights), - l4_map_obj_control(mapped_cap.index, L4_MAP_ITEM_MAP))); -} - -static long map_capabilities(l4_cap_idx_t task, struct mapped_cap mapped_caps[]) -{ - long err = L4_EOK; - - for (int i = 0; l4_is_valid_cap(mapped_caps[i].cap) && !err; i++) - err = map_capability(task, mapped_caps[i]); - - return err; -} - - - -/* A stack abstraction. */ - -class Stack -{ - struct auxv_entry - { - l4_umword_t key, value; - }; - -protected: - Segment &_segment; - - /* Next element pointer. */ - - l4_umword_t *_element; - - /* Stack section properties. */ - - l4_addr_t _caps; - char *_arg_top, *_env_top; - char **_argv; - char *_auxv_end; - int _env_entries; - - /* L4Re auxiliary and environment regions. */ - - l4re_aux_t *_aux; - l4re_env_t *_env; - -public: - /* Start address. */ - - l4_addr_t start; - - /* Initialise a stack in a memory segment. */ - - explicit Stack(Segment &segment) - : _segment(segment) - { - _element = (l4_umword_t *) (segment.buf + segment.size); - - /* Add a terminator for any additional initial capabilities. */ - - l4re_env_cap_entry_t *entry = (l4re_env_cap_entry_t *) _element; - - *(--entry) = l4re_env_cap_entry_t(); - _element = (l4_umword_t *) entry; - } - - /* Push any additional initial capabilities. */ - - void push_cap_entries(l4re_env_cap_entry_t *entries) - { - l4re_env_cap_entry_t *entry = (l4re_env_cap_entry_t *) _element; - - while ((entries != NULL) && (entries->cap != L4_INVALID_CAP)) - *(--entry) = *entries; - - _caps = (l4_addr_t) entry; - _element = (l4_umword_t *) entry; - } - - /* Push environment values in reverse order. */ - - void push_string(char *s) - { - char *arg = (char *) _element; - char *arg_last = arg; - - arg -= round(strlen(s) + 1, sizeof(l4_umword_t)); - - memset(arg, 0, arg_last - arg); - memcpy(arg, s, strlen(s)); - - _element = (l4_umword_t *) arg; - } - - /* Push environment values in reverse order. */ - - void push_env(char *envp[]) - { - _env_top = (char *) _element; - _env_entries = 0; - - for (; *envp != NULL; envp++, _env_entries++) - push_string(*envp); - } - - /* Push argument values in reverse order. */ - - void push_args(int argc, char *argv[]) - { - _arg_top = (char *) _element; - - for (int i = 0; i < argc; i++) - push_string(argv[i]); - } - - /* Loader flags, debugging flags, and the KIP capability index. - See: generate_l4aux in Remote_app_model */ - - void push_l4re_aux() - { - _aux = (l4re_aux_t *) _element; - _aux--; - _element = (l4_umword_t *) _aux; - } - - void push_l4re_env() - { - _env = (l4re_env_t *) _element; - _env--; - _element = (l4_umword_t *) _env; - } - - /* Set the common auxiliary information. */ - - void set_l4re_aux(l4re_aux_t *aux) - { - memcpy(_aux, aux, sizeof(l4re_aux_t)); - - /* Take the binary name from the first program argument. */ - - _aux->binary = (char *) _argv[0]; - } - - /* Set the common environment, introducing the reference to additional - capabilities. */ - - void set_l4re_env(l4re_env_t *env) - { - memcpy(_env, env, sizeof(l4re_env_t)); - _env->caps = (l4re_env_cap_entry_t *) (_segment.region_address(_caps)); - } - - /* Push the auxiliary vector. */ - - void push_auxv() - { - _auxv_end = (char *) _element; - - struct auxv_entry *auxv_base = (struct auxv_entry *) _element; - - /* AUXV NULL. */ - - *(--auxv_base) = {0, 0}; - - /* L4Re global environment pointer. */ - - *(--auxv_base) = {0xf1, _segment.region_address((char *) _env)}; - - /* L4Re auxiliary structure pointer. */ - - *(--auxv_base) = {0xf0, _segment.region_address((char *) _aux)}; - - /* Apparently required entries. - NOTE: The user/group identifiers should be obtained from the broader - environment. */ - - *(--auxv_base) = {AT_PAGESZ, L4_PAGESIZE}; - *(--auxv_base) = {AT_UID, 0}; - *(--auxv_base) = {AT_EUID, 0}; - *(--auxv_base) = {AT_GID, 0}; - *(--auxv_base) = {AT_EGID, 0}; - - _element = (l4_umword_t *) auxv_base; - } - - /* Fill the stack in reverse with an address, returning the size of the - value. */ - - offset_t write_address(char *arg, char **addr, char *s) - { - offset_t size = round(strlen(s) + 1, sizeof(l4_umword_t)); - - *addr = (char *) _segment.region_address(arg - size); - return size; - } - - /* Populate stack with environment pointers, employing a pointer ordering - that is the reverse of the value ordering. */ - - void push_envp(char *envp[]) - { - /* Write the terminating element. */ - - *(--_element) = 0; - - /* Reserve space and fill the stack from the top inwards. */ - - char **ep = (char **) (_element - _env_entries); - char *arg = _env_top; - - for (; *envp != NULL; envp++, ep++) - arg -= write_address(arg, ep, *envp); - - _element -= _env_entries; - } - - /* Populate stack with argument pointers and count, employing a pointer - ordering that is the reverse of the value ordering. */ - - void push_argv(int argc, char *argv[]) - { - /* Write the terminating element. */ - - *(--_element) = 0; - - /* Reserve space and fill the stack from the top inwards. */ - - _argv = (char **) (_element - argc); - char *arg = _arg_top; - - for (int i = 0; i < argc; i++) - arg -= write_address(arg, &_argv[i], argv[i]); - - /* Write the count. */ - - _element -= argc; - - *(--_element) = argc; - } - - /* Adjust the stack alignment and return the stack address. */ - - l4_addr_t align_stack() - { - char *current = (char *) _element; - char *adjusted = Ldr::adjust_sp(current, NULL); - - if (adjusted != current) - memmove(adjusted, (const void *) current, _auxv_end - current); - - _element = (l4_umword_t *) adjusted; - - return _segment.region_address(adjusted); - } - - /* Populate the stack with arguments and initial environment. */ - - void populate(int argc, char *argv[], char *envp[]) - { - /* Populate stack with environment and argument values. */ - - push_env(envp); - push_args(argc, argv); - - /* Push L4Re flags, environment and auxiliary vector. */ - - push_l4re_aux(); - push_l4re_env(); - push_auxv(); - - /* Push environment and argument pointers. */ - - push_envp(envp); - push_argv(argc, argv); - - /* Adjust the stack alignment. */ - - start = align_stack(); - } -}; - - - -class Process -{ -protected: - l4_cap_idx_t _task = L4_INVALID_CAP; - - /* Capability index definitions. */ - - l4_cap_idx_t _pager_cap = 0x10 << L4_CAP_SHIFT; - l4_cap_idx_t _rm_cap = 0x11 << L4_CAP_SHIFT; - l4_cap_idx_t _ma_cap = 0x12 << L4_CAP_SHIFT; - l4_cap_idx_t _kip_cap = 0x14 << L4_CAP_SHIFT; - unsigned int _first_cap = 0x15; - - /* UTCB details. */ - - l4_addr_t _utcb_start; - - /* Common environment details. */ - - l4re_aux_t _aux; - l4re_env_t _env; - - /* Task and thread initialisation. */ - - long create_task() - { - _task = ipc_cap_alloc(); - - if (l4_is_invalid_cap(_task)) - return -L4_ENOMEM; - - return l4_error(l4_factory_create_task(l4re_env()->factory, _task, _env.utcb_area)); - } - - long create_thread(l4_cap_idx_t *thread) - { - *thread = ipc_cap_alloc(); - - if (l4_is_invalid_cap(*thread)) - return -L4_ENOMEM; - - return l4_error(l4_factory_create_thread(l4re_env()->factory, *thread)); - } - -public: - explicit Process() - { - /* Obtain UTCB area details for the task. */ - - l4_fpage_t utcb_fpage = get_utcb_fpage(); - - _utcb_start = l4_fpage_memaddr(utcb_fpage); - - /* Populate the common initial environment for the threads. */ - - _env.factory = L4_BASE_FACTORY_CAP; - _env.main_thread = L4_BASE_THREAD_CAP; - _env.log = L4_BASE_LOG_CAP; - _env.scheduler = L4_BASE_SCHEDULER_CAP; - _env.rm = _rm_cap; - _env.mem_alloc = _ma_cap; - _env.first_free_cap = _first_cap; - _env.utcb_area = utcb_fpage; - _env.first_free_utcb = l4_fpage_memaddr(utcb_fpage) + L4_UTCB_OFFSET; - - /* Populate auxiliary information. */ - - _aux.kip_ds = _kip_cap; - _aux.dbg_lvl = 0; - _aux.ldr_flags = 0; - } - - /* Configure the task environment. */ - - long configure(l4_cap_idx_t server) - { - long err = create_task(); - - if (err) - return err; - - /* Map the KIP into the task. */ - - l4_addr_t kip_start = (l4_addr_t) l4re_kip(); - - err = l4_error(l4_task_map(_task, L4RE_THIS_TASK_CAP, - l4_fpage(kip_start, L4_PAGESHIFT, L4_FPAGE_RX), - kip_start)); - - if (err) - return err; - - /* Define capability mappings for the new task. */ - - struct mapped_cap mapped_caps[] = { - {L4_BASE_TASK_CAP, _task, L4_CAP_FPAGE_RWS}, - {_pager_cap, server, L4_CAP_FPAGE_RWS}, - {_env.rm, server, L4_CAP_FPAGE_RWS}, - {_env.factory, l4re_env()->factory, L4_CAP_FPAGE_RWS}, - {_env.log, l4re_env()->log, L4_CAP_FPAGE_RWS}, - {_env.scheduler, l4re_env()->scheduler, L4_CAP_FPAGE_RWS}, - {_env.mem_alloc, l4re_env()->mem_alloc, L4_CAP_FPAGE_RWS}, - {0, L4_INVALID_CAP, 0}, - }; - - return map_capabilities(_task, mapped_caps); - } - - /* Create, initialise and start a thread. */ - - long thread_start(l4_addr_t program_start, Stack &st) - { - l4_cap_idx_t thread; - long err; - - err = create_thread(&thread); - - if (err) - return err; - - /* Initialise the thread with pager, UTCB and task details. */ - - l4_thread_control_start(); - l4_thread_control_pager(_pager_cap); - l4_thread_control_exc_handler(_pager_cap); - l4_thread_control_bind((l4_utcb_t *) _utcb_start, _task); - - err = l4_error(l4_thread_control_commit(thread)); - - if (err) - { - ipc_cap_free(thread); - return err; - } - - /* Map the thread capability to the task. */ - - map_capability(_task, (struct mapped_cap) {_env.main_thread, thread, L4_CAP_FPAGE_RWS}); - - /* Populate the initial environment in the thread. */ - - st.set_l4re_aux(&_aux); - st.set_l4re_env(&_env); - - /* Set the start details. */ - - err = l4_error(l4_thread_ex_regs(thread, program_start, st.start, 0)); - - if (err) - return err; - - /* Select a new address for the next thread. */ - - _utcb_start += L4_UTCB_OFFSET; - - /* Start the thread. */ - - l4_sched_param_t sp = l4_sched_param(L4RE_MAIN_THREAD_PRIO); - - return l4_error(l4_scheduler_run_thread(l4re_env()->scheduler, thread, &sp)); - } -}; - - - class PayloadBase { public: