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