lin
2025-08-01 633231e833e21d5b8b1c00cb15aedb62b3b78e8f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
 
#include "address_mapper.h"
 
#include <stdint.h>
 
#include <vector>
 
#include "base/logging.h"
 
namespace quipper {
 
AddressMapper::AddressMapper(const AddressMapper& other) {
  // Copy over most members naively.
  mappings_ = other.mappings_;
  page_alignment_ = other.page_alignment_;
 
  // Reconstruct mapping of real addresses to mapped ranges.
  for (auto iter = mappings_.begin(); iter != mappings_.end(); ++iter) {
    real_addr_to_mapped_range_[iter->real_addr] = iter;
  }
}
 
bool AddressMapper::MapWithID(const uint64_t real_addr, const uint64_t size,
                              const uint64_t id, const uint64_t offset_base,
                              bool remove_existing_mappings) {
  if (size == 0) {
    LOG(ERROR) << "Must allocate a nonzero-length address range.";
    return false;
  }
 
  // Check that this mapping does not overflow the address space.
  if (real_addr + size - 1 != UINT64_MAX && !(real_addr + size > real_addr)) {
    DumpToLog();
    LOG(ERROR) << "Address mapping at " << std::hex << real_addr
               << " with size " << std::hex << size << " overflows.";
    return false;
  }
 
  MappedRange range;
  range.real_addr = real_addr;
  range.size = size;
  range.id = id;
  range.offset_base = offset_base;
 
  // Check for collision with an existing mapping. This must be an overlap that
  // does not result in one range being completely covered by another.
 
  // First determine the range of mappings that could overlap with the new
  // mapping in real space.
 
  // lower_bound returns the first range with starting addr >= |real_addr|. The
  // preceding range could also possibly overlap with the new range.
  auto map_iter_start = real_addr_to_mapped_range_.lower_bound(real_addr);
  if (map_iter_start != real_addr_to_mapped_range_.begin()) --map_iter_start;
  // lower_bound returns the first range with starting addr beyond the end of
  // the new mapping range.
  auto map_iter_end = real_addr_to_mapped_range_.lower_bound(real_addr + size);
 
  std::vector<MappingList::iterator> mappings_to_delete;
  MappingList::iterator old_range_iter = mappings_.end();
  for (auto map_iter = map_iter_start; map_iter != map_iter_end; ++map_iter) {
    auto iter = map_iter->second;
    if (!iter->Intersects(range)) continue;
    // Quit if existing ranges that collide aren't supposed to be removed.
    if (!remove_existing_mappings) return false;
    if (old_range_iter == mappings_.end() && iter->Covers(range) &&
        iter->size > range.size) {
      old_range_iter = iter;
      continue;
    }
    mappings_to_delete.push_back(iter);
  }
 
  for (MappingList::iterator mapping_iter : mappings_to_delete)
    Unmap(mapping_iter);
  mappings_to_delete.clear();
 
  // Otherwise check for this range being covered by another range.  If that
  // happens, split or reduce the existing range to make room.
  if (old_range_iter != mappings_.end()) {
    // Make a copy of the old mapping before removing it.
    const MappedRange old_range = *old_range_iter;
    Unmap(old_range_iter);
 
    uint64_t gap_before = range.real_addr - old_range.real_addr;
    uint64_t gap_after =
        (old_range.real_addr + old_range.size) - (range.real_addr + range.size);
 
    // If the new mapping is not aligned to a page boundary at either its start
    // or end, it will require the end of the old mapping range to be moved,
    // which is not allowed.
    if (page_alignment_) {
      if ((gap_before && GetAlignedOffset(range.real_addr)) ||
          (gap_after && GetAlignedOffset(range.real_addr + range.size))) {
        LOG(ERROR) << "Split mapping must result in page-aligned mappings.";
        return false;
      }
    }
 
    if (gap_before) {
      if (!MapWithID(old_range.real_addr, gap_before, old_range.id,
                     old_range.offset_base, false)) {
        LOG(ERROR) << "Could not map old range from " << std::hex
                   << old_range.real_addr << " to "
                   << old_range.real_addr + gap_before;
        return false;
      }
    }
 
    if (!MapWithID(range.real_addr, range.size, id, offset_base, false)) {
      LOG(ERROR) << "Could not map new range at " << std::hex << range.real_addr
                 << " to " << range.real_addr + range.size << " over old range";
      return false;
    }
 
    if (gap_after) {
      if (!MapWithID(range.real_addr + range.size, gap_after, old_range.id,
                     old_range.offset_base + gap_before + range.size, false)) {
        LOG(ERROR) << "Could not map old range from " << std::hex
                   << old_range.real_addr << " to "
                   << old_range.real_addr + gap_before;
        return false;
      }
    }
 
    return true;
  }
 
  // Now search for a location for the new range.  It should be in the first
  // free block in quipper space.
 
  uint64_t page_offset =
      page_alignment_ ? GetAlignedOffset(range.real_addr) : 0;
 
  // If there is no existing mapping, add it to the beginning of quipper space.
  if (IsEmpty()) {
    range.mapped_addr = page_offset;
    range.unmapped_space_after = UINT64_MAX - range.size - page_offset;
    mappings_.push_back(range);
    real_addr_to_mapped_range_.insert(
        std::make_pair(range.real_addr, mappings_.begin()));
    return true;
  }
 
  // If there is space before the first mapped range in quipper space, use it.
  if (mappings_.begin()->mapped_addr >= range.size + page_offset) {
    range.mapped_addr = page_offset;
    range.unmapped_space_after =
        mappings_.begin()->mapped_addr - range.size - page_offset;
    mappings_.push_front(range);
    MappingList::iterator iter = mappings_.begin();
    real_addr_to_mapped_range_.insert(std::make_pair(range.real_addr, iter));
    return true;
  }
 
  // Otherwise, search through the existing mappings for a free block after one
  // of them.
  for (auto iter = mappings_.begin(); iter != mappings_.end(); ++iter) {
    MappedRange& existing_mapping = *iter;
    if (page_alignment_) {
      uint64_t end_of_existing_mapping =
          existing_mapping.mapped_addr + existing_mapping.size;
 
      // Find next page boundary after end of this existing mapping.
      uint64_t existing_page_offset = GetAlignedOffset(end_of_existing_mapping);
      uint64_t next_page_boundary =
          existing_page_offset
              ? end_of_existing_mapping - existing_page_offset + page_alignment_
              : end_of_existing_mapping;
      // Compute where the new mapping would end if it were aligned to this
      // page boundary.
      uint64_t mapping_offset = GetAlignedOffset(range.real_addr);
      uint64_t end_of_new_mapping =
          next_page_boundary + mapping_offset + range.size;
      uint64_t end_of_unmapped_space_after =
          end_of_existing_mapping + existing_mapping.unmapped_space_after;
 
      // Check if there's enough room in the unmapped space following the
      // current existing mapping for the page-aligned mapping.
      if (end_of_new_mapping > end_of_unmapped_space_after) continue;
 
      range.mapped_addr = next_page_boundary + mapping_offset;
      range.unmapped_space_after =
          end_of_unmapped_space_after - end_of_new_mapping;
      existing_mapping.unmapped_space_after =
          range.mapped_addr - end_of_existing_mapping;
    } else {
      if (existing_mapping.unmapped_space_after < range.size) continue;
      // Insert the new mapping range immediately after the existing one.
      range.mapped_addr = existing_mapping.mapped_addr + existing_mapping.size;
      range.unmapped_space_after =
          existing_mapping.unmapped_space_after - range.size;
      existing_mapping.unmapped_space_after = 0;
    }
 
    mappings_.insert(++iter, range);
    --iter;
    real_addr_to_mapped_range_.insert(std::make_pair(range.real_addr, iter));
    return true;
  }
 
  // If it still hasn't succeeded in mapping, it means there is no free space in
  // quipper space large enough for a mapping of this size.
  DumpToLog();
  LOG(ERROR) << "Could not find space to map addr=" << std::hex << real_addr
             << " with size " << std::hex << size;
  return false;
}
 
void AddressMapper::DumpToLog() const {
  MappingList::const_iterator it;
  for (it = mappings_.begin(); it != mappings_.end(); ++it) {
    LOG(INFO) << " real_addr: " << std::hex << it->real_addr
              << " mapped: " << std::hex << it->mapped_addr
              << " id: " << std::hex << it->id
              << " size: " << std::hex << it->size;
  }
}
 
bool AddressMapper::GetMappedAddressAndListIterator(
    const uint64_t real_addr, uint64_t* mapped_addr,
    MappingList::const_iterator* iter) const {
  CHECK(mapped_addr);
  CHECK(iter);
 
  *iter = GetRangeContainingAddress(real_addr);
  if (*iter == mappings_.end()) return false;
  *mapped_addr = (*iter)->mapped_addr + real_addr - (*iter)->real_addr;
  return true;
}
 
void AddressMapper::GetMappedIDAndOffset(
    const uint64_t real_addr, MappingList::const_iterator real_addr_iter,
    uint64_t* id, uint64_t* offset) const {
  CHECK(real_addr_iter != mappings_.end());
  CHECK(id);
  CHECK(offset);
 
  *id = real_addr_iter->id;
  *offset = real_addr - real_addr_iter->real_addr + real_addr_iter->offset_base;
}
 
uint64_t AddressMapper::GetMaxMappedLength() const {
  if (IsEmpty()) return 0;
 
  uint64_t min = mappings_.begin()->mapped_addr;
 
  MappingList::const_iterator iter = mappings_.end();
  --iter;
  uint64_t max = iter->mapped_addr + iter->size;
 
  return max - min;
}
 
void AddressMapper::Unmap(MappingList::iterator mapping_iter) {
  // Add the freed up space to the free space counter of the previous
  // mapped region, if it exists.
  if (mapping_iter != mappings_.begin()) {
    const MappedRange& range = *mapping_iter;
    MappingList::iterator previous_range_iter = std::prev(mapping_iter);
    previous_range_iter->unmapped_space_after +=
        range.size + range.unmapped_space_after;
  }
  real_addr_to_mapped_range_.erase(mapping_iter->real_addr);
  mappings_.erase(mapping_iter);
}
 
AddressMapper::MappingList::const_iterator
AddressMapper::GetRangeContainingAddress(uint64_t real_addr) const {
  // Find the first range that has a higher real address than the given one.
  MappingMap::const_iterator target_map_iter =
      real_addr_to_mapped_range_.upper_bound(real_addr);
 
  if (target_map_iter == real_addr_to_mapped_range_.begin()) {
    // The lowest real address in existing mappings is higher than the new
    // mapping address, so |real_addr| does not fall into any mapping.
    return mappings_.end();
  }
 
  // Otherwise, the previous mapping could possibly contain |real_addr|.
  --target_map_iter;
  MappingList::const_iterator list_iter = target_map_iter->second;
  if (!list_iter->ContainsAddress(real_addr)) return mappings_.end();
 
  return list_iter;
}
 
}  // namespace quipper