1 /* 2 * Generic pager functionality. 3 * 4 * Copyright (C) 2021, 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 "dataspace_server.h" 23 #include "ipc.h" 24 #include "pager.h" 25 26 #include "copied_page_mapper.h" 27 #include "masked_page_mapper.h" 28 29 30 31 /* Initialise the pager with a page mapper and the given flags controlling 32 access to a file. */ 33 34 Pager::Pager(GenericPageMapper *mapper, map_flags_t flags) 35 : _start(0), _size(0), 36 _mapper(mapper), _mapper_base(mapper), _mapper_masked(NULL), 37 _mapper_copied(NULL), 38 _flags(flags) 39 { 40 } 41 42 /* Close the pager. */ 43 44 void Pager::close() 45 { 46 if (_mapper_masked != NULL) 47 { 48 delete _mapper_masked; 49 _mapper_masked = NULL; 50 } 51 52 if (_mapper_copied != NULL) 53 { 54 delete _mapper_copied; 55 _mapper_copied = NULL; 56 } 57 } 58 59 /* Flush data to the file. */ 60 61 long Pager::flush(offset_t populated_size, offset_t *size) 62 { 63 _mapper->flush_all(_start, populated_size); 64 65 *size = _mapper->get_data_size(); 66 return L4_EOK; 67 } 68 69 /* Resize the underlying file. */ 70 71 long Pager::resize(offset_t *size) 72 { 73 _mapper->set_data_size(*size); 74 75 *size = _mapper->get_data_size(); 76 return L4_EOK; 77 } 78 79 /* Expose a region of the file. */ 80 81 long Pager::mmap(offset_t position, offset_t length, 82 offset_t start_visible, offset_t end_visible, 83 offset_t *start_pos, offset_t *end_pos, offset_t *size) 84 { 85 /* Define region characteristics. */ 86 87 _start = trunc(position, PAGE_SIZE); 88 _size = round(position + length, PAGE_SIZE) - _start; 89 90 /* Return the start and end positions plus populated extent. */ 91 92 *start_pos = _start; 93 *end_pos = _start + _size; 94 *size = _mapper_base->get_data_size(); 95 96 /* Permit masking of mapped regions. */ 97 98 if ((start_visible || end_visible) && 99 ((*start_pos != start_visible) || (*end_pos != end_visible))) 100 { 101 /* Introduce the masked page and copied page mappers. */ 102 103 _mapper_masked = new MaskedPageMapper(_mapper_base, start_visible, end_visible); 104 _mapper_copied = new CopiedPageMapper(_mapper_masked); 105 _mapper = _mapper_copied; 106 } 107 else 108 _mapper = _mapper_base; 109 110 return L4_EOK; 111 } 112 113 /* Map a flexpage corresponding to the dataspace 'offset' involving a 'hot_spot' 114 (flexpage offset). */ 115 116 long Pager::map(offset_t offset, address_t hot_spot, map_flags_t flags, 117 l4_snd_fpage_t *region) 118 { 119 offset_t file_offset = _start + offset; 120 offset_t max_offset = _start + _size; 121 122 /* Prevent access beyond that defined by the pager. 123 NOTE: Permitting executable requests here. This needs to be configured 124 when opening the pager or by another means. */ 125 126 if (flags & (~(_flags | L4RE_DS_F_X))) 127 return -L4_EACCESS; 128 129 /* Obtain a flexpage from the page mapper. */ 130 131 Flexpage *flexpage = _mapper->get(file_offset, flags); 132 133 /* Issue the flexpage via the IPC system. */ 134 135 long err = ipc_prepare_flexpage(flexpage, file_offset, max_offset, 136 hot_spot, flags, region); 137 138 if (!err) 139 err = complete_Dataspace_map(*region); 140 141 /* After the obtained flexpage is issued, it is queued for future reuse, if 142 appropriate for the mapper concerned. */ 143 144 _mapper->queue(flexpage); 145 146 if (err) 147 return err; 148 149 return IPC_MESSAGE_SENT; 150 } 151 152 /* Return the total size of the data. */ 153 154 offset_t Pager::get_data_size() 155 { 156 return _mapper->get_data_size(); 157 } 158 159 // vim: tabstop=4 expandtab shiftwidth=4