# HG changeset patch # User Paul Boddie # Date 1654208470 -7200 # Node ID 8328ce61f006fb4009b7cca9da275e93c2ee8233 # Parent 6d3b22ac818ff1fe7d21fe2d381c840bb211104b Integrated the different segment classes and moved segment initialisation to a library module. The program stack is now initialised separately. diff -r 6d3b22ac818f -r 8328ce61f006 libexec/include/exec/elf.h --- a/libexec/include/exec/elf.h Thu Jun 02 01:09:30 2022 +0200 +++ b/libexec/include/exec/elf.h Fri Jun 03 00:21:10 2022 +0200 @@ -19,27 +19,16 @@ * Boston, MA 02110-1301, USA */ +#pragma once + #include /* Generic program segment interface. */ -class ProgramSegment -{ -public: - virtual bool loadable() = 0; - virtual offset_t file_contents() = 0; - virtual offset_t file_offset() = 0; - virtual l4_addr_t region_address() = 0; - virtual offset_t region_size() = 0; - virtual l4re_rm_flags_t region_flags() = 0; - - Segment *segment(); -}; - template -class ProgramSegmentVariant : public ProgramSegment +class ProgramSegmentVariant : public Segment { protected: PROGRAM_HEADER *_header; @@ -55,18 +44,23 @@ l4re_rm_flags_t region_flags(); }; - + /* Generic interface for an ELF payload. */ class Payload { +protected: + Segment **_segments = NULL; + public: + virtual ~Payload(); + virtual l4_addr_t entry_point() = 0; virtual offset_t header_extent() = 0; virtual offset_t program_header_extent() = 0; - virtual unsigned int segments() = 0; - virtual ProgramSegment *segment(unsigned int i) = 0; + virtual unsigned int segments(); + virtual Segment *segment(unsigned int i) = 0; }; template @@ -82,7 +76,7 @@ offset_t header_extent(); offset_t program_header_extent(); unsigned int segments(); - ProgramSegment *segment(unsigned int i); + Segment *segment(unsigned int i); }; diff -r 6d3b22ac818f -r 8328ce61f006 libexec/include/exec/memory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/include/exec/memory.h Fri Jun 03 00:21:10 2022 +0200 @@ -0,0 +1,32 @@ +/* + * Program memory initialisation 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 + + + +long exec_get_payload(const char *filename, Payload **payload); + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 6d3b22ac818f -r 8328ce61f006 libexec/include/exec/segment.h --- a/libexec/include/exec/segment.h Thu Jun 02 01:09:30 2022 +0200 +++ b/libexec/include/exec/segment.h Fri Jun 03 00:21:10 2022 +0200 @@ -30,7 +30,7 @@ -/* Program segment abstraction. */ +/* Program segment abstractions. */ class Segment { @@ -42,29 +42,24 @@ char *_buf; l4re_ds_t _ds; - /* Segment base and corresponding region base. */ + /* Segment region base. */ - l4_addr_t _base, _region_base; + l4_addr_t _region_base; - /* Segment size and corresponding region size. */ + /* Segment region size. */ - offset_t _size, _region_size; + offset_t _region_allocated_size; /* Offset of segment content within the region. */ - offset_t _region_offset; - - /* Access flags. */ + offset_t _region_content_offset; - l4re_rm_flags_t _flags; + /* Common initialisation. */ - /* File access details. */ - - offset_t _file_offset, _file_contents; + void init(); public: - explicit Segment(l4_addr_t base, offset_t size, l4re_rm_flags_t flags, - offset_t file_offset = 0, offset_t file_contents = 0); + virtual ~Segment(); char *address(); @@ -86,8 +81,46 @@ /* Generic property access. */ + virtual bool loadable() = 0; + virtual offset_t file_contents() = 0; + virtual offset_t file_offset() = 0; + virtual l4_addr_t region_address() = 0; + virtual offset_t region_size() = 0; + virtual l4re_rm_flags_t region_flags() = 0; +}; + + + +class ExplicitSegment : public Segment +{ +protected: + /* Segment base. */ + + l4_addr_t _base; + + /* Segment size. */ + + offset_t _size; + + /* Access flags. */ + + l4re_rm_flags_t _flags; + + /* File access details. */ + + offset_t _file_offset, _file_contents; + +public: + explicit ExplicitSegment(l4_addr_t base, offset_t size, l4re_rm_flags_t flags, + offset_t file_offset = 0, offset_t file_contents = 0); + + /* Generic property access. */ + + bool loadable(); offset_t file_contents(); - + offset_t file_offset(); + l4_addr_t region_address(); + offset_t region_size(); l4re_rm_flags_t region_flags(); }; diff -r 6d3b22ac818f -r 8328ce61f006 libexec/lib/src/Makefile --- a/libexec/lib/src/Makefile Thu Jun 02 01:09:30 2022 +0200 +++ b/libexec/lib/src/Makefile Fri Jun 03 00:21:10 2022 +0200 @@ -3,7 +3,7 @@ TARGET = libexec.a libexec.so PC_FILENAME = libexec -SRC_CC = elf.cc process.cc segment.cc stack.cc +SRC_CC = elf.cc memory.cc process.cc segment.cc stack.cc REQUIRES_LIBS = l4re_c-util libmem libipc libstdc++ libsystypes libfsclient PRIVATE_INCDIR += $(PKGDIR)/include/exec diff -r 6d3b22ac818f -r 8328ce61f006 libexec/lib/src/elf.cc --- a/libexec/lib/src/elf.cc Thu Jun 02 01:09:30 2022 +0200 +++ b/libexec/lib/src/elf.cc Fri Jun 03 00:21:10 2022 +0200 @@ -25,26 +25,13 @@ -/* Generic segment creation from program segments. */ - -Segment *ProgramSegment::segment() -{ - return new Segment( - region_address(), - region_size(), - region_flags(), - file_offset(), - file_contents()); -} - - - /* Program segment construction for 32- or 64-bit variants. */ template ProgramSegmentVariant::ProgramSegmentVariant(PROGRAM_HEADER *header) : _header(header) { + init(); } template @@ -94,6 +81,24 @@ +/* Generic payload destruction. */ + +Payload::~Payload() +{ + if (_segments != NULL) + { + for (unsigned int i = 0; i < segments(); i++) + delete _segments[i]; + } +} + +unsigned int Payload::segments() +{ + return 0; +} + + + /* ELF payload construction for 32- or 64-bit variants. */ template @@ -127,14 +132,30 @@ } template -ProgramSegment *PayloadVariant::segment(unsigned int i) +Segment *PayloadVariant::segment(unsigned int i) { if (i >= segments()) return NULL; - return new ProgramSegmentVariant( - (PROGRAM_HEADER *) ((char *) _header + _header->e_phoff + - _header->e_phentsize * i)); + if (_segments == NULL) + { + _segments = new Segment *[segments()]; + + for (unsigned int j = 0; j < segments(); j++) + _segments[j] = NULL; + } + + Segment *segment = _segments[i]; + + if (segment == NULL) + { + segment = new ProgramSegmentVariant( + (PROGRAM_HEADER *) ((char *) _header + _header->e_phoff + + _header->e_phentsize * i)); + _segments[i] = segment; + } + + return segment; } diff -r 6d3b22ac818f -r 8328ce61f006 libexec/lib/src/memory.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libexec/lib/src/memory.cc Fri Jun 03 00:21:10 2022 +0200 @@ -0,0 +1,92 @@ +/* + * Support for initialising program memory regions in new 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 + +#include "memory.h" + + + +/* Obtain the payload as a dataspace. */ + +long exec_get_payload(const char *filename, Payload **payload) +{ + file_t *file = client_open(filename, O_RDONLY); + + if (file == NULL) + return -L4_EIO; + + /* Obtain metadata from the file. */ + + char *buf = (char *) client_mmap(file, 0, file->size, 0, 0, L4RE_DS_F_R); + + /* Test the file type indicator. */ + + if ((file->size < EI_NIDENT) || memcmp(buf, "\x7f" "ELF", 4)) + return -L4_EINVAL; + + /* Attempt to get a payload object appropriate for a particular object size + variant. */ + + *payload = get_payload(buf); + + if ((*payload == NULL) || + (file->size < (*payload)->header_extent()) || + (file->size < (*payload)->program_header_extent())) + return -L4_ERANGE; + + /* Obtain all loadable segments. */ + + for (unsigned int i = 0; i < (*payload)->segments(); i++) + { + Segment *segment = (*payload)->segment(i); + long err; + + if (!segment->loadable()) + continue; + + if (segment->file_contents()) + { + file_t *rfile = client_open(filename, file_opening_flags(segment->region_flags())); + + if (rfile == NULL) + return -L4_EIO; + + err = segment->fill(rfile); + } + else + err = segment->allocate(); + + if (err) + return err; + } + + return L4_EOK; +} + +/* vim: tabstop=2 expandtab shiftwidth=2 +*/ diff -r 6d3b22ac818f -r 8328ce61f006 libexec/lib/src/segment.cc --- a/libexec/lib/src/segment.cc Thu Jun 02 01:09:30 2022 +0200 +++ b/libexec/lib/src/segment.cc Fri Jun 03 00:21:10 2022 +0200 @@ -31,20 +31,22 @@ -/* Initialise a memory segment. */ +/* Obligatory destructor. */ -Segment::Segment(l4_addr_t base, offset_t size, l4re_rm_flags_t flags, - offset_t file_offset, offset_t file_contents) +Segment::~Segment() +{ +} -: _base(base), _size(size), _flags(flags), _file_offset(file_offset), - _file_contents(file_contents) +/* Common initialisation. */ + +void Segment::init() { - _region_base = trunc(_base, L4_PAGESIZE); - _region_offset = _base - _region_base; + _region_base = trunc(region_address(), L4_PAGESIZE); + _region_content_offset = region_address() - _region_base; /* Expand the region size. */ - _region_size = round(_size + _region_offset, L4_PAGESIZE); + _region_allocated_size = round(region_size() + _region_content_offset, L4_PAGESIZE); } /* Return the address of allocated memory. */ @@ -58,14 +60,14 @@ offset_t Segment::size() { - return _region_size; + return _region_allocated_size; } /* Allocate a writable region for the segment. */ long Segment::allocate() { - return ipc_allocate_align(_region_size, L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW, + return ipc_allocate_align(_region_allocated_size, L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW, L4_PAGESHIFT, (void **) &_buf, &_ds); } @@ -76,11 +78,11 @@ /* Provide the exposed file contents in a masked memory mapped region. */ _buf = (char *) client_mmap(file, - _file_offset - _region_offset, - _region_size, - _file_offset, - _file_offset + _file_contents, - _flags); + file_offset() - _region_content_offset, + _region_allocated_size, + file_offset(), + file_offset() + file_contents(), + region_flags()); if (_buf == NULL) return -L4_EIO; @@ -92,7 +94,7 @@ MappedRegion &Segment::region() { - _region = MappedRegion((l4_addr_t) _buf, _region_size, _flags, _region_base); + _region = MappedRegion((l4_addr_t) _buf, _region_allocated_size, region_flags(), _region_base); return _region; } @@ -108,16 +110,49 @@ return (address - (l4_addr_t) _buf) + _region_base; } + + +/* Initialise a memory segment using explicit parameters. */ + +ExplicitSegment::ExplicitSegment(l4_addr_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) +{ + init(); +} + /* Return the amount of file content loaded into the segment. */ -offset_t Segment::file_contents() +bool ExplicitSegment::loadable() +{ + return false; +} + +offset_t ExplicitSegment::file_contents() { return _file_contents; } +offset_t ExplicitSegment::file_offset() +{ + return _file_offset; +} + +l4_addr_t ExplicitSegment::region_address() +{ + return _base; +} + +offset_t ExplicitSegment::region_size() +{ + return _size; +} + /* Return the region flags for the segment. */ -l4re_rm_flags_t Segment::region_flags() +l4re_rm_flags_t ExplicitSegment::region_flags() { return _flags; } diff -r 6d3b22ac818f -r 8328ce61f006 tests/dstest_exec.cc --- a/tests/dstest_exec.cc Thu Jun 02 01:09:30 2022 +0200 +++ b/tests/dstest_exec.cc Fri Jun 03 00:21:10 2022 +0200 @@ -20,18 +20,15 @@ */ #include -#include #include -#include #include #include +#include #include -#include #include #include #include -#include #include @@ -319,115 +316,22 @@ return 1; } - /* Obtain the payload as a dataspace. */ - - file_t *file = client_open(argv[1], O_RDONLY); - - if (file == NULL) - { - printf("Could not read file: %s\n", argv[1]); - return 1; - } - - /* Obtain metadata from the file. */ - - char *buf = (char *) client_mmap(file, 0, file->size, 0, 0, L4RE_DS_F_R); - - if ((file->size < EI_NIDENT) || memcmp(buf, "\x7f" "ELF", 4)) - { - printf("Not an ELF payload: %s\n", argv[1]); - return 1; - } + /* Initialise the memory of the new task. */ - Payload *payload = get_payload(buf); + offset_t initial_stack_size = 16 * L4_PAGESIZE; + ExplicitSegment stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW); + Payload *payload; - if (payload == NULL) - { - printf("Unrecognised object size.\n"); - return 1; - } - - if (file->size < payload->header_extent()) + if (exec_get_payload(argv[1], &payload)) { - printf("Header incomplete.\n"); - return 1; - } - - printf("Program start: %lx\n", payload->entry_point()); - - if (file->size < payload->program_header_extent()) - { - printf("Program headers incomplete.\n"); + printf("Could not initialise program.\n"); return 1; } - /* Make appropriate segments, although program segments could be made - interoperable with these. */ - - Segment *segments[payload->segments() + 1]; - - for (unsigned int i = 0; i < payload->segments(); i++) - { - ProgramSegment *ps = payload->segment(i); - - printf("Segment(0x%lx, 0x%lx, 0x%x, 0x%lx, 0x%lx): %s\n", - ps->region_address(), - ps->region_size(), - ps->region_flags(), - ps->file_offset(), - ps->file_contents(), - ps->loadable() ? "loadable" : "other"); - - if (ps->loadable()) - segments[i] = ps->segment(); - else - segments[i] = NULL; - } - - /* Copy the payload regions to new dataspaces. */ - - address_t program_start = payload->entry_point(); - offset_t initial_stack_size = 16 * L4_PAGESIZE; - - Segment stack(Utcb_area_start - initial_stack_size, initial_stack_size, L4_FPAGE_RW); - - segments[payload->segments()] = &stack; - - for (unsigned int i = 0; i < payload->segments() + 1; i++) + if (stack.allocate()) { - Segment *segment = segments[i]; - - if (segment == NULL) - continue; - - if (segment->file_contents()) - { - file_t *file = client_open(argv[1], file_opening_flags(segment->region_flags())); - - if (file == NULL) - { - printf("Could not open file for segment.\n"); - return 1; - } - - err = segment->fill(file); - - if (err) - { - printf("Could not fill segment from file.\n"); - return 1; - } - } - else - { - err = segment->allocate(); - - if (err) - { - printf("Could not allocate segment.\n"); - return 1; - } - } + printf("Could not allocate stack.\n"); + return 1; } /* Start the pager. */ @@ -441,15 +345,13 @@ init_pager(&config); - for (unsigned int i = 0; i < payload->segments() + 1; i++) + for (unsigned int i = 0; i < payload->segments(); i++) { - Segment *segment = segments[i]; + if (payload->segment(i)->loadable()) + exec_pager.add(payload->segment(i)->region()); + } - if (segment == NULL) - continue; - - exec_pager.add(segment->region()); - } + exec_pager.add(stack.region()); err = pthread_create(&pager_thread, &attr, ipc_server_start_mainloop, &config); @@ -494,7 +396,7 @@ printf("Run thread...\n"); - err = process.thread_start(program_start, st); + err = process.thread_start(payload->entry_point(), st); if (err) {