1 // Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "address_mapper.h"
7 #include "base/logging.h"
11 AddressMapper::AddressMapper(const AddressMapper& source) {
12 mappings_ = source.mappings_;
15 bool AddressMapper::Map(const uint64_t real_addr,
17 const bool remove_existing_mappings) {
18 return MapWithID(real_addr, size, kuint64max, 0, remove_existing_mappings);
21 bool AddressMapper::MapWithID(const uint64_t real_addr,
24 const uint64_t offset_base,
25 bool remove_existing_mappings) {
27 range.real_addr = real_addr;
30 range.offset_base = offset_base;
33 LOG(ERROR) << "Must allocate a nonzero-length address range.";
37 // Check that this mapping does not overflow the address space.
38 if (real_addr + size - 1 != kuint64max &&
39 !(real_addr + size > real_addr)) {
41 LOG(ERROR) << "Address mapping at " << std::hex << real_addr
42 << " with size " << std::hex << size << " overflows.";
46 // Check for collision with an existing mapping. This must be an overlap that
47 // does not result in one range being completely covered by another
48 MappingList::iterator iter;
49 MappingList mappings_to_delete;
50 bool old_range_found = false;
51 MappedRange old_range;
52 for (iter = mappings_.begin(); iter != mappings_.end(); ++iter) {
53 if (!iter->Intersects(range))
55 // Quit if existing ranges that collide aren't supposed to be removed.
56 if (!remove_existing_mappings)
58 if (!old_range_found && iter->Covers(range) && iter->size > range.size) {
59 old_range_found = true;
63 mappings_to_delete.push_back(*iter);
66 while (!mappings_to_delete.empty()) {
67 const MappedRange& range = mappings_to_delete.front();
69 mappings_to_delete.pop_front();
72 // Otherwise check for this range being covered by another range. If that
73 // happens, split or reduce the existing range to make room.
74 if (old_range_found) {
75 CHECK(Unmap(old_range));
77 uint64_t gap_before = range.real_addr - old_range.real_addr;
78 uint64_t gap_after = (old_range.real_addr + old_range.size) -
79 (range.real_addr + range.size);
82 CHECK(MapWithID(old_range.real_addr,
85 old_range.offset_base,
89 CHECK(MapWithID(range.real_addr, range.size, id, offset_base, false));
92 CHECK(MapWithID(range.real_addr + range.size,
95 old_range.offset_base + gap_before + range.size,
102 // Now search for a location for the new range. It should be in the first
103 // free block in quipper space.
105 // If there is no existing mapping, add it to the beginning of quipper space.
106 if (mappings_.empty()) {
107 range.mapped_addr = 0;
108 range.unmapped_space_after = kuint64max - range.size;
109 mappings_.push_back(range);
113 // If there is space before the first mapped range in quipper space, use it.
114 if (mappings_.begin()->mapped_addr >= range.size) {
115 range.mapped_addr = 0;
116 range.unmapped_space_after = mappings_.begin()->mapped_addr - range.size;
117 mappings_.push_front(range);
121 // Otherwise, search through the existing mappings for a free block after one
123 for (iter = mappings_.begin(); iter != mappings_.end(); ++iter) {
124 if (iter->unmapped_space_after < range.size)
127 range.mapped_addr = iter->mapped_addr + iter->size;
128 range.unmapped_space_after = iter->unmapped_space_after - range.size;
129 iter->unmapped_space_after = 0;
131 mappings_.insert(++iter, range);
135 // If it still hasn't succeeded in mapping, it means there is no free space in
136 // quipper space large enough for a mapping of this size.
138 LOG(ERROR) << "Could not find space to map addr=" << std::hex << real_addr
139 << " with size " << std::hex << size;
143 void AddressMapper::DumpToLog() const {
144 MappingList::const_iterator it;
145 for (it = mappings_.begin(); it != mappings_.end(); ++it) {
146 LOG(INFO) << " real_addr: " << std::hex << it->real_addr
147 << " mapped: " << std::hex << it->mapped_addr
148 << " id: " << std::hex << it->id
149 << " size: " << std::hex << it->size;
153 bool AddressMapper::GetMappedAddress(const uint64_t real_addr,
154 uint64_t* mapped_addr) const {
156 MappingList::const_iterator iter;
157 for (iter = mappings_.begin(); iter != mappings_.end(); ++iter) {
158 if (!iter->ContainsAddress(real_addr))
160 *mapped_addr = iter->mapped_addr + real_addr - iter->real_addr;
166 bool AddressMapper::GetMappedIDAndOffset(const uint64_t real_addr,
168 uint64_t* offset) const {
171 MappingList::const_iterator iter;
172 for (iter = mappings_.begin(); iter != mappings_.end(); ++iter) {
173 if (!iter->ContainsAddress(real_addr))
176 *offset = real_addr - iter->real_addr + iter->offset_base;
182 uint64_t AddressMapper::GetMaxMappedLength() const {
186 uint64_t min = mappings_.begin()->mapped_addr;
188 MappingList::const_iterator iter = mappings_.end();
190 uint64_t max = iter->mapped_addr + iter->size;
195 bool AddressMapper::Unmap(const MappedRange& range) {
196 MappingList::iterator iter;
197 // TODO(sque): this is highly inefficient since Unmap() is called from a
198 // function that has already iterated to the right place within |mappings_|.
199 // For a first revision, I am sacrificing efficiency for of clarity, due to
200 // the trickiness of removing elements using iterators.
201 for (iter = mappings_.begin(); iter != mappings_.end(); ++iter) {
202 if (range.real_addr == iter->real_addr && range.size == iter->size) {
203 // Add the freed up space to the free space counter of the previous
204 // mapped region, if it exists.
205 if (iter != mappings_.begin()) {
207 iter->unmapped_space_after += range.size + range.unmapped_space_after;
210 mappings_.erase(iter);
217 } // namespace quipper