1 /* 2 * Generic pager functionality. 3 * 4 * Copyright (C) 2021 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 27 28 /* Initialise the pager with a page mapper and the given flags controlling 29 access to a file. */ 30 31 Pager::Pager(PageMapper *mapper, flags_t flags) 32 : _start(0), _size(0), _mapper(mapper), _flags(flags) 33 { 34 /* Some pagers may not be initialised with a mapper. */ 35 36 if (_mapper != NULL) 37 _mapper->attach(); 38 } 39 40 /* Close the pager. */ 41 42 void Pager::close() 43 { 44 if (_mapper != NULL) 45 _mapper->detach(); 46 } 47 48 /* Flush data to the file. */ 49 50 long Pager::flush(offset_t populated_size, offset_t *size) 51 { 52 _mapper->flush_all(_start, populated_size); 53 54 *size = _mapper->get_data_size(); 55 return L4_EOK; 56 } 57 58 /* Resize the underlying file. */ 59 60 long Pager::resize(offset_t *size) 61 { 62 _mapper->set_data_size(*size); 63 64 *size = _mapper->get_data_size(); 65 return L4_EOK; 66 } 67 68 /* Expose a region of the file. */ 69 70 long Pager::mmap(offset_t position, offset_t length, offset_t *start_pos, 71 offset_t *end_pos, offset_t *size) 72 { 73 /* Define region characteristics. */ 74 75 _start = trunc(position, PAGE_SIZE); 76 _size = round(position + length, PAGE_SIZE) - _start; 77 78 /* Return the start and end positions plus populated extent. */ 79 80 *start_pos = _start; 81 *end_pos = _start + _size; 82 *size = _mapper->get_data_size(); 83 84 return L4_EOK; 85 } 86 87 /* Map a flexpage corresponding to the dataspace 'offset' involving a 'hot_spot' 88 (flexpage offset). */ 89 90 long Pager::map(offset_t offset, address_t hot_spot, flags_t flags, 91 l4_snd_fpage_t *region) 92 { 93 offset_t file_offset = _start + offset; 94 offset_t max_offset = _start + _size; 95 96 /* Prevent access beyond that defined by the pager. */ 97 98 if (flags & ~_flags) 99 return -L4_EACCESS; 100 101 Flexpage *flexpage = _mapper->get(file_offset, flags); 102 103 /* Issue the flexpage via the IPC system. */ 104 105 long err = ipc_prepare_flexpage(flexpage, file_offset, max_offset, hot_spot, 106 flags, region); 107 108 if (!err) 109 err = complete_Dataspace_map(*region); 110 111 /* After the flexpage is issued, it is queued for future reuse. */ 112 113 _mapper->queue(flexpage); 114 115 if (err) 116 return err; 117 118 return IPC_MESSAGE_SENT; 119 } 120 121 /* Return the total size of the data. */ 122 123 offset_t Pager::get_data_size() 124 { 125 return _mapper->get_data_size(); 126 } 127 128 // vim: tabstop=4 expandtab shiftwidth=4