1 /* 2 * Common system pager functionality. 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/re/env.h> 23 #include <l4/re/c/rm.h> 24 25 #include <mem/memory_utils.h> 26 27 #include "pager.h" 28 29 30 31 /* Initialise common functionality. */ 32 33 ExecPager::ExecPager(address_t start, address_t end) 34 : _start(start), _end(end) 35 { 36 } 37 38 /* Necessary virtual destructor. */ 39 40 ExecPager::~ExecPager() 41 { 42 } 43 44 45 46 /* Add a region to the pager. */ 47 48 void ExecPager::add(MappedRegion ®ion) 49 { 50 _regions[region.start] = region; 51 } 52 53 /* Remove a region from the pager. */ 54 55 void ExecPager::remove(MappedRegion ®ion) 56 { 57 _regions.erase(region.start); 58 } 59 60 61 62 /* Attach a region for provision when page faults occur. */ 63 64 long ExecPager::find(address_t *start, address_t *size, map_flags_t flags, 65 address_t offset, unsigned char align) 66 { 67 if (align < L4_PAGESHIFT) 68 align = L4_PAGESHIFT; 69 70 /* Obtain the alignment increment and a properly aligned size. */ 71 72 address_t increment = 1UL << align; 73 address_t region_size = round(*size, increment); 74 75 /* Either attempt to find an address for the specified region, starting from 76 any indicated address. */ 77 78 if (flags & L4RE_RM_F_SEARCH_ADDR) 79 { 80 /* Align any desired location. */ 81 82 address_t region_start = trunc(*start, increment); 83 84 /* Enforce a minimum address. */ 85 86 if (region_start < _start) 87 region_start = round(_start, increment); 88 89 /* Search for existing regions after the desired, conformant address. */ 90 91 MappedRegions::iterator it = _regions.upper_bound(region_start); 92 93 /* Consider any region preceding or encompassing the desired address. */ 94 95 if (it != _regions.begin()) 96 { 97 MappedRegions::iterator next = it; 98 99 /* Step back to the preceding region to get its details. */ 100 101 it--; 102 MappedRegion &pr = it->second; 103 address_t previous_end = pr.start + pr.size; 104 it = next; 105 106 /* The preceding region may displace the desired region location if it 107 is encompassed by the region. */ 108 109 if (region_start < previous_end) 110 region_start = round(previous_end, increment); 111 } 112 113 /* Consider the regions following the current region start candidate. */ 114 115 while ((it != _regions.end()) && !(_end && ((region_start + region_size) > _end))) 116 { 117 MappedRegion &r = it->second; 118 119 /* Obtain the limit of available space being considered. */ 120 121 address_t end_limit = r.start; 122 123 /* Investigate subsequent regions if not enough space exists between the 124 preceding region (or start of memory) and the current region. */ 125 126 if ((region_start + region_size) > end_limit) 127 { 128 region_start = round(r.start + r.size, increment); 129 it++; 130 } 131 132 /* Otherwise, the region can be positioned. */ 133 134 else 135 break; 136 } 137 138 /* Test for enough memory constrained by any predefined limit. */ 139 140 if (_end && ((region_start + region_size) > _end)) 141 return -L4_ENOMEM; 142 143 /* Return the configured start and size. */ 144 145 *start = region_start; 146 *size = region_size; 147 return L4_EOK; 148 } 149 150 /* Or attempt to add the specified region at a specific address. */ 151 152 else 153 { 154 // NOTE: To be implemented. 155 156 return -L4_ENOMEM; 157 } 158 } 159 160 /* vim: tabstop=2 expandtab shiftwidth=2 161 */