1 /* 2 * A flexpage abstraction. 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 <algorithm> 23 24 #include "flexpage.h" 25 26 27 28 /* Reset the flexpage using 'offset', being the file offset. */ 29 30 void Flexpage::reset(offset_t offset) 31 { 32 _counter = 0; 33 34 /* By definition (see "Flexible-Sized Page Objects - Object-Orientation 35 in Operation Systems"), flexpages are aligned to multiples of their 36 size. 37 38 The size of the flexpage depends on the amount of space around the 39 accessed page. It cannot exceed the size of the memory region. */ 40 41 size = max_multiple(region->start, region->end, PAGE_SIZE); 42 43 /* The base address of the flexpage is computed from the region start 44 and flexpage size. It will be no lower than the region start. 45 46 Sent flexpages may use higher bases due to receive window constraints, 47 these being communicated by the "hot spot". */ 48 49 base_addr = round(region->start, size); 50 51 /* Get the file offset for the base of the flexpage. This will be a 52 multiple of the flexpage size for alignment purposes. */ 53 54 base_offset = trunc(offset, size); 55 56 /* The page being accessed is relative to the base. 57 (This is transient information recording the initialising access 58 details.) */ 59 60 page_offset = trunc(offset - base_offset, PAGE_SIZE); 61 page_addr = base_addr + page_offset; 62 } 63 64 bool Flexpage::decrement() 65 { 66 if (_counter) 67 { 68 _counter--; 69 return _counter == 0; 70 } 71 else 72 return 0; 73 } 74 75 void Flexpage::increment() 76 { 77 _counter++; 78 } 79 80 void Flexpage::invalidate() 81 { 82 _counter = 0; 83 } 84 85 bool Flexpage::valid() 86 { 87 return _counter != 0; 88 } 89 90 /* Return whether the flexpage supports the given file 'position'. */ 91 92 bool Flexpage::supports_position(offset_t position) 93 { 94 return (base_offset <= position) && (position < (base_offset + size)); 95 } 96 97 /* Upgrade the flags involved with this flexpage. This is used to track the 98 maximal flags employed by the different pagers, with the result being used in 99 unmap operations. */ 100 101 void Flexpage::upgrade(flags_t flags) 102 { 103 if (flags && (flags != _flags)) 104 _flags |= flags; 105 } 106 107 /* Return a "send" flexpage for an access to 'offset' by positioning it relative 108 to 'hot_spot' for the receive flexpage window. */ 109 110 SendFlexpage Flexpage::to_send(offset_t offset, offset_t hot_spot, 111 flags_t flags, offset_t max_offset) 112 { 113 /* The dataspace offset of the flexpage base is a multiple of the flexpage 114 size. */ 115 116 offset_t receive_base_offset = trunc(offset, size); 117 118 /* The offset of the accessed page within the flexpage is constrained by the 119 current flexpage size. */ 120 121 offset_t page_offset = trunc(offset - receive_base_offset, PAGE_SIZE); 122 123 /* The receive flexpage offset (hot spot) must be constrained to the 124 flexpage, both the size and the start. */ 125 126 offset_t receive_size; 127 128 if (max_offset) 129 { 130 receive_size = trunc_multiple(max_offset - receive_base_offset, PAGE_SIZE); 131 receive_size = std::min(size, receive_size); 132 } 133 else 134 receive_size = size; 135 136 if (!receive_size) 137 return SendFlexpage(base_addr, page_order(0), flags); 138 139 offset_t receive_page_offset = hot_spot % receive_size; 140 141 while ((receive_size > PAGE_SIZE) && (receive_page_offset != page_offset)) 142 { 143 receive_size /= 2; 144 receive_page_offset = hot_spot % receive_size; 145 } 146 147 /* The flexpage base address is adjusted using the difference in page 148 offsets. Where the receive flexpage offset is constained further, the 149 base address will be raised to become closer to the accessed page. */ 150 151 offset_t adjustment = page_offset - receive_page_offset; 152 153 return SendFlexpage(base_addr + adjustment, page_order(receive_size), flags); 154 } 155 156 /* Return a representation of the flexpage for unmapping. */ 157 158 SendFlexpage Flexpage::to_unmap() 159 { 160 return SendFlexpage(base_addr, page_order(size), _flags); 161 } 162 163 // vim: tabstop=4 expandtab shiftwidth=4