1 /* 2 * Program memory segment support. 3 * 4 * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <l4/sys/err.h> 23 24 #include <ipc/mem_ipc.h> 25 #include <mem/memory_utils.h> 26 27 #include <stdio.h> 28 #include <string.h> 29 30 #include "segment.h" 31 32 33 34 /* Obligatory destructor. */ 35 36 Segment::~Segment() 37 { 38 } 39 40 /* Common initialisation. */ 41 42 void Segment::init() 43 { 44 _region_base = trunc(region_address(), L4_PAGESIZE); 45 _region_content_offset = region_address() - _region_base; 46 47 /* Expand the region size. */ 48 49 _region_allocated_size = round(region_size() + _region_content_offset, L4_PAGESIZE); 50 } 51 52 /* Return the capability of the dataspace providing the memory. */ 53 54 l4_cap_idx_t Segment::cap() 55 { 56 return _ds; 57 } 58 59 /* Return the address of allocated memory. */ 60 61 char *Segment::address() 62 { 63 return _buf; 64 } 65 66 /* Return the size of the allocated memory. */ 67 68 offset_t Segment::size() 69 { 70 return _region_allocated_size; 71 } 72 73 /* Allocate a writable region for the segment. */ 74 75 long Segment::allocate(bool attach) 76 { 77 if (attach) 78 return ipc_allocate_align(_region_allocated_size, 79 L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW, 80 L4_PAGESHIFT, (void **) &_buf, &_ds); 81 else 82 return ipc_new_dataspace(_region_allocated_size, 83 L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW, 84 L4_PAGESHIFT, &_ds); 85 } 86 87 /* Fill a segment region with file content. */ 88 89 long Segment::fill(file_t *file, bool attach) 90 { 91 /* Provide the exposed file contents in a masked memory mapped region, or if 92 not attaching the region, merely request access via a dataspace. */ 93 94 if (attach) 95 { 96 _buf = (char *) client_mmap(file, 97 file_offset() - _region_content_offset, 98 _region_allocated_size, 99 file_offset(), 100 file_offset() + file_contents(), 101 region_flags()); 102 if (_buf == NULL) 103 return -L4_EIO; 104 } 105 else 106 { 107 long err = file_mmap_only(file, 108 file_offset() - _region_content_offset, 109 _region_allocated_size, 110 file_offset(), 111 file_offset() + file_contents()); 112 if (err) 113 return err; 114 } 115 116 _ds = file->ref; 117 return L4_EOK; 118 } 119 120 /* Define and return the mapped region for the segment. */ 121 122 MappedRegion &Segment::region() 123 { 124 _region = MappedRegion((l4_addr_t) _buf, _region_allocated_size, region_flags(), _region_base, _ds); 125 return _region; 126 } 127 128 /* Define and return the region dataspace details. */ 129 130 struct exec_region &Segment::exec_region() 131 { 132 _exec_region = (struct exec_region) {_region_base, _region_allocated_size, region_flags(), _ds}; 133 return _exec_region; 134 } 135 136 /* Return the mapped address corresponding to the given address. */ 137 138 l4_addr_t Segment::region_address(char *address) 139 { 140 return (l4_addr_t) ((address - _buf) + (char *) _region_base); 141 } 142 143 l4_addr_t Segment::region_address(l4_addr_t address) 144 { 145 return (address - (l4_addr_t) _buf) + _region_base; 146 } 147 148 149 150 /* Initialise a memory segment using explicit parameters. */ 151 152 ExplicitSegment::ExplicitSegment(l4_addr_t base, offset_t size, 153 l4re_rm_flags_t flags, offset_t file_offset, 154 offset_t file_contents) 155 : _base(base), _size(size), _flags(flags), _file_offset(file_offset), 156 _file_contents(file_contents) 157 { 158 init(); 159 } 160 161 /* Return the amount of file content loaded into the segment. */ 162 163 bool ExplicitSegment::loadable() 164 { 165 return false; 166 } 167 168 offset_t ExplicitSegment::file_contents() 169 { 170 return _file_contents; 171 } 172 173 offset_t ExplicitSegment::file_offset() 174 { 175 return _file_offset; 176 } 177 178 l4_addr_t ExplicitSegment::region_address() 179 { 180 return _base; 181 } 182 183 offset_t ExplicitSegment::region_size() 184 { 185 return _size; 186 } 187 188 /* Return the region flags for the segment. */ 189 190 l4re_rm_flags_t ExplicitSegment::region_flags() 191 { 192 return _flags; 193 } 194 195 /* vim: tabstop=2 expandtab shiftwidth=2 196 */