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