1 /* 2 * A page mapper providing copied memory pages or deferring to another page 3 * mapper to satisfy file accesses. 4 * 5 * Copyright (C) 2021, 2022 Paul Boddie <paul@boddie.org.uk> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA 21 */ 22 23 #include <l4/re/c/dataspace.h> 24 25 #include <string.h> 26 27 #include "copied_page_mapper.h" 28 29 30 31 /* Provide mapped pages populated with the given 'mapper', with pages obtained 32 from the given 'pages' collection. */ 33 34 CopiedPageMapper::CopiedPageMapper(GenericPageMapper *mapper) 35 : _mapper(mapper) 36 { 37 _size = _mapper->get_data_size(); 38 } 39 40 /* Upon deallocation, release allocated flexpages. */ 41 42 CopiedPageMapper::~CopiedPageMapper() 43 { 44 while (!_queue.empty()) 45 { 46 Flexpage *flexpage = _queue.front(); 47 48 _queue.pop_front(); 49 _memory.release(flexpage->region); 50 delete flexpage; 51 } 52 } 53 54 /* Interface for the pager. */ 55 56 /* Return a flexpage providing access to the indicated file 'offset'. 57 58 The returned flexpage will either provide direct access to the underlying 59 file content or be a completely new flexpage modified through writes to 60 memory. */ 61 62 Flexpage *CopiedPageMapper::get(offset_t offset, map_flags_t flags) 63 { 64 Flexpage *f = find(offset); 65 66 /* Defer to the underlying page mapper if no flexpage was found. */ 67 68 if (f == NULL) 69 { 70 f = _mapper->get(offset, flags); 71 72 /* Replicate the underlying flexpage if writing. */ 73 74 if (flags & L4RE_DS_F_W) 75 { 76 Flexpage *rf = replicate_flexpage(offset, f); 77 _mapper->queue(f); 78 f = rf; 79 } 80 } 81 82 /* Upgrade the access flags. */ 83 84 f->upgrade(flags); 85 return f; 86 } 87 88 /* Queue the given 'flexpage'. */ 89 90 void CopiedPageMapper::queue(Flexpage *flexpage) 91 { 92 if (dynamic_cast<CopiedFlexpage *>(flexpage) == NULL) 93 _mapper->queue(flexpage); 94 } 95 96 /* Flush pages in the given range from 'start' with 'size'. */ 97 98 void CopiedPageMapper::flush_all(offset_t start, offset_t size) 99 { 100 /* NOTE: This might be superfluous since copy-on-write regions should not 101 update content. */ 102 103 _mapper->flush_all(start, size); 104 } 105 106 /* Return the maximum extent of the mapped resource. */ 107 108 offset_t CopiedPageMapper::get_data_size() 109 { 110 return _size; 111 } 112 113 /* Set the maximum extent of the mapped resource. */ 114 115 void CopiedPageMapper::set_data_size(offset_t size) 116 { 117 _size = size; 118 } 119 120 /* Internal flexpage retrieval methods. */ 121 122 /* Find an existing flexpage for 'offset'. */ 123 124 Flexpage *CopiedPageMapper::find(offset_t offset) 125 { 126 return _map.find(offset); 127 } 128 129 /* Replicate an underlying flexpage for the file 'offset' using the given 130 'flexpage'. */ 131 132 Flexpage *CopiedPageMapper::replicate_flexpage(offset_t offset, Flexpage *flexpage) 133 { 134 /* Obtain a new memory region and a new flexpage. */ 135 136 Region *region = _memory.region(flexpage->size); 137 Flexpage *replicated = new CopiedFlexpage(region); 138 139 /* Configure the flexpage for the file region. */ 140 141 replicated->reset(offset); 142 143 /* Copy the contents of the underlying flexpage. */ 144 145 memcpy((void *) region->start, (const void *) flexpage->region->start, flexpage->size); 146 147 /* Register the flexpage for future accesses and for deallocation. */ 148 149 _map.insert(replicated); 150 _queue.push_back(replicated); 151 return replicated; 152 } 153 154 155 156 /* Copied flexpage constructor. */ 157 158 CopiedFlexpage::CopiedFlexpage(Region *region) 159 : Flexpage(region) 160 { 161 } 162 163 // vim: tabstop=4 expandtab shiftwidth=4