// 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.
|
|
#ifndef CHROMIUMOS_WIDE_PROFILING_ADDRESS_MAPPER_H_
|
#define CHROMIUMOS_WIDE_PROFILING_ADDRESS_MAPPER_H_
|
|
#include <stddef.h>
|
#include <stdint.h>
|
|
#include <list>
|
#include <map>
|
|
namespace quipper {
|
|
class AddressMapper {
|
private:
|
struct MappedRange;
|
|
public:
|
AddressMapper() : page_alignment_(0) {}
|
|
// Copy constructor: copies mappings from |source| to this AddressMapper. This
|
// is useful for copying mappings from parent to child process upon fork(). It
|
// is also useful to copy kernel mappings to any process that is created.
|
AddressMapper(const AddressMapper& other);
|
|
typedef std::list<MappedRange> MappingList;
|
|
// Maps a new address range [real_addr, real_addr + length) to quipper space.
|
// |id| is an identifier value to be stored along with the mapping.
|
// AddressMapper does not care whether it is unique compared to all other IDs
|
// passed in. That is up to the caller to keep track of.
|
// |offset_base| represents the offset within the original region at which the
|
// mapping begins. The original region can be much larger than the mapped
|
// region.
|
// e.g. Given a mapped region with base=0x4000 and size=0x2000 mapped with
|
// offset_base=0x10000, then the address 0x5000 maps to an offset of 0x11000
|
// (0x5000 - 0x4000 + 0x10000).
|
// |remove_existing_mappings| indicates whether to remove old mappings that
|
// collide with the new range in real address space, indicating it has been
|
// unmapped.
|
// Returns true if mapping was successful.
|
bool MapWithID(const uint64_t real_addr, const uint64_t size,
|
const uint64_t id, const uint64_t offset_base,
|
bool remove_existing_mappings);
|
|
// Looks up |real_addr| and returns the mapped address and MappingList
|
// iterator.
|
bool GetMappedAddressAndListIterator(const uint64_t real_addr,
|
uint64_t* mapped_addr,
|
MappingList::const_iterator* iter) const;
|
|
// Uses MappingList iterator to fetch and return the mapping's ID and offset
|
// from the start of the mapped space.
|
// |real_addr_iter| must be valid and not at the end of the list.
|
void GetMappedIDAndOffset(const uint64_t real_addr,
|
MappingList::const_iterator real_addr_iter,
|
uint64_t* id, uint64_t* offset) const;
|
|
// Returns true if there are no mappings.
|
bool IsEmpty() const { return mappings_.empty(); }
|
|
// Returns the number of address ranges that are currently mapped.
|
size_t GetNumMappedRanges() const { return mappings_.size(); }
|
|
// Returns the maximum length of quipper space containing mapped areas.
|
// There may be gaps in between blocks.
|
// If the result is 2^64 (all of quipper space), this returns 0. Call
|
// IsEmpty() to distinguish this from actual emptiness.
|
uint64_t GetMaxMappedLength() const;
|
|
// Sets the page alignment size. Set to 0 to disable page alignment.
|
// The alignment value must be a power of two. Any other value passed in will
|
// have no effect. Changing this value in between mappings results in
|
// undefined behavior.
|
void set_page_alignment(uint64_t alignment) {
|
// This also includes the case of 0.
|
if ((alignment & (alignment - 1)) == 0) page_alignment_ = alignment;
|
}
|
|
// Dumps the state of the address mapper to logs. Useful for debugging.
|
void DumpToLog() const;
|
|
private:
|
typedef std::map<uint64_t, MappingList::iterator> MappingMap;
|
|
struct MappedRange {
|
uint64_t real_addr;
|
uint64_t mapped_addr;
|
uint64_t size;
|
|
uint64_t id;
|
uint64_t offset_base;
|
|
// Length of unmapped space after this range.
|
uint64_t unmapped_space_after;
|
|
// Determines if this range intersects another range in real space.
|
inline bool Intersects(const MappedRange& range) const {
|
return (real_addr <= range.real_addr + range.size - 1) &&
|
(real_addr + size - 1 >= range.real_addr);
|
}
|
|
// Determines if this range fully covers another range in real space.
|
inline bool Covers(const MappedRange& range) const {
|
return (real_addr <= range.real_addr) &&
|
(real_addr + size - 1 >= range.real_addr + range.size - 1);
|
}
|
|
// Determines if this range fully contains another range in real space.
|
// This is different from Covers() in that the boundaries cannot overlap.
|
inline bool Contains(const MappedRange& range) const {
|
return (real_addr < range.real_addr) &&
|
(real_addr + size - 1 > range.real_addr + range.size - 1);
|
}
|
|
// Determines if this range contains the given address |addr|.
|
inline bool ContainsAddress(uint64_t addr) const {
|
return (addr >= real_addr && addr <= real_addr + size - 1);
|
}
|
};
|
|
// Returns an iterator to a MappedRange in |mappings_| that contains
|
// |real_addr|. Returns |mappings_.end()| if no range contains |real_addr|.
|
MappingList::const_iterator GetRangeContainingAddress(
|
uint64_t real_addr) const;
|
|
// Removes an existing address mapping, given by an iterator pointing to an
|
// element of |mappings_|.
|
void Unmap(MappingList::iterator mapping_iter);
|
|
// Given an address, and a nonzero, power-of-two |page_alignment_| value,
|
// returns the offset of the address from the start of the page it is on.
|
// Equivalent to |addr % page_alignment_|. Should not be called if
|
// |page_alignment_| is zero.
|
uint64_t GetAlignedOffset(uint64_t addr) const {
|
return addr & (page_alignment_ - 1);
|
}
|
|
// Container for all the existing mappings.
|
MappingList mappings_;
|
|
// Maps real addresses to iterators pointing to entries within |mappings_|.
|
// Must maintain a 1:1 entry correspondence with |mappings_|.
|
MappingMap real_addr_to_mapped_range_;
|
|
// If set to nonzero, use this as a mapping page boundary. If a mapping does
|
// not begin at a multiple of this value, the remapped address should be given
|
// an offset that is the remainder.
|
//
|
// e.g. if alignment=0x1000 and a mapping starts at 0x520100, then the
|
// remapping should treat the mapping as starting at 0x520000, but addresses
|
// are only valid starting at 0x520100.
|
uint64_t page_alignment_;
|
};
|
|
} // namespace quipper
|
|
#endif // CHROMIUMOS_WIDE_PROFILING_ADDRESS_MAPPER_H_
|