1 /* 2 * Program memory segment support. 3 * 4 * Copyright (C) 2022, 2023 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/cap_alloc.h> 25 #include <ipc/mem_ipc.h> 26 #include <mem/memory_utils.h> 27 28 #include <stdio.h> 29 #include <string.h> 30 31 #include "segment.h" 32 33 34 35 /* Free the allocated resources. */ 36 37 Segment::~Segment() 38 { 39 if (_allocated) 40 { 41 if (_attached) 42 ipc_detach_dataspace(_buf); 43 44 /* Also unmap the dataspace, not apparently done by the underlying 45 functions. */ 46 47 if (l4_is_valid_cap(_ds)) 48 ipc_cap_free_um(_ds); 49 } 50 else if (client_opened(_file)) 51 { 52 client_close(_file); 53 _file = NULL; 54 } 55 } 56 57 /* Common initialisation. */ 58 59 void Segment::init() 60 { 61 _region_base = trunc(region_address(), L4_PAGESIZE); 62 _region_content_offset = region_address() - _region_base; 63 64 /* Expand the region size. */ 65 66 _region_allocated_size = round(region_size() + _region_content_offset, L4_PAGESIZE); 67 } 68 69 /* Return the capability of the dataspace providing the memory. */ 70 71 l4_cap_idx_t Segment::cap() 72 { 73 return _ds; 74 } 75 76 /* Return the address of allocated memory. */ 77 78 char *Segment::address() 79 { 80 return _buf; 81 } 82 83 /* Return the size of the allocated memory. */ 84 85 offset_t Segment::size() 86 { 87 return _region_allocated_size; 88 } 89 90 /* Allocate a writable region for the segment. */ 91 92 long Segment::allocate(bool attach) 93 { 94 _allocated = true; 95 _attached = attach; 96 97 if (attach) 98 return ipc_allocate_align(_region_allocated_size, 99 L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW, 100 L4_PAGESHIFT, (void **) &_buf, &_ds); 101 else 102 return ipc_new_dataspace(_region_allocated_size, 103 L4RE_RM_F_SEARCH_ADDR | L4RE_RM_F_RW, 104 L4_PAGESHIFT, &_ds); 105 } 106 107 /* Fill a segment region with file content. */ 108 109 long Segment::fill(file_t *file, bool attach) 110 { 111 /* Provide the exposed file contents in a masked memory mapped region, or if 112 not attaching the region, merely request access via a dataspace. */ 113 114 if (attach) 115 { 116 _buf = (char *) client_mmap(file, 117 file_offset() - _region_content_offset, 118 _region_allocated_size, 119 file_offset(), 120 file_offset() + file_contents(), 121 region_flags()); 122 if (_buf == NULL) 123 return -L4_EIO; 124 } 125 else 126 { 127 long err = file_mmap_only(file, 128 file_offset() - _region_content_offset, 129 _region_allocated_size, 130 file_offset(), 131 file_offset() + file_contents()); 132 if (err) 133 return err; 134 } 135 136 _file = file; 137 _ds = file->ref; 138 return L4_EOK; 139 } 140 141 /* Define and return the mapped region for the segment. */ 142 143 MappedRegion &Segment::region() 144 { 145 _region = MappedRegion(_region_base, _region_base + _region_allocated_size, 146 region_flags(), _ds, (l4_addr_t) _buf); 147 return _region; 148 } 149 150 /* Define and return the region dataspace details. */ 151 152 struct exec_region &Segment::exec_region() 153 { 154 _exec_region = (struct exec_region) {_region_base, _region_allocated_size, region_flags(), _ds}; 155 return _exec_region; 156 } 157 158 /* Return the mapped address corresponding to the given address. */ 159 160 l4_addr_t Segment::region_address(char *address) 161 { 162 return (l4_addr_t) ((address - _buf) + (char *) _region_base); 163 } 164 165 l4_addr_t Segment::region_address(l4_addr_t address) 166 { 167 return (address - (l4_addr_t) _buf) + _region_base; 168 } 169 170 171 172 /* Initialise a memory segment using explicit parameters. */ 173 174 ExplicitSegment::ExplicitSegment(l4_addr_t base, offset_t size, 175 l4re_rm_flags_t flags, offset_t file_offset, 176 offset_t file_contents) 177 : _base(base), _size(size), _flags(flags), _file_offset(file_offset), 178 _file_contents(file_contents) 179 { 180 init(); 181 } 182 183 /* Return the amount of file content loaded into the segment. */ 184 185 bool ExplicitSegment::loadable() 186 { 187 return false; 188 } 189 190 offset_t ExplicitSegment::file_contents() 191 { 192 return _file_contents; 193 } 194 195 offset_t ExplicitSegment::file_offset() 196 { 197 return _file_offset; 198 } 199 200 l4_addr_t ExplicitSegment::region_address() 201 { 202 return _base; 203 } 204 205 offset_t ExplicitSegment::region_size() 206 { 207 return _size; 208 } 209 210 /* Return the region flags for the segment. */ 211 212 l4re_rm_flags_t ExplicitSegment::region_flags() 213 { 214 return _flags; 215 } 216 217 /* vim: tabstop=2 expandtab shiftwidth=2 218 */