| // Copyright 2017 The Fuchsia 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 SRC_LIB_DDK_INCLUDE_DDK_PHYS_ITER_H_ |
| #define SRC_LIB_DDK_INCLUDE_DDK_PHYS_ITER_H_ |
| |
| #include <zircon/types.h> |
| |
| __BEGIN_CDECLS |
| |
| // An entry in a scatter gather list. |
| typedef struct { |
| // length starting at the scatter gather entry offset, must be non zero |
| size_t length; |
| // offset relative to the buffer's vmo_offset |
| size_t offset; |
| } phys_iter_sg_entry_t; |
| |
| // Specifies the buffer to iterate over. |
| typedef struct { |
| const zx_paddr_t* phys; // list of physical addresses backing the buffer starting at vmo_offset |
| uint64_t phys_count; // number of entries in phys list |
| |
| size_t length; // length of the buffer starting at vmo_offset, used if scatter gather |
| // list is not present |
| uint64_t vmo_offset; // offset into first page to start iterating on |
| |
| const phys_iter_sg_entry_t* sg_list; // optional list of scatter gather entries to iterate over |
| size_t sg_count; // number of entries in the scatter gather list |
| } phys_iter_buffer_t; |
| |
| // Used to iterate over contiguous buffer ranges in the physical address space. |
| typedef struct { |
| phys_iter_buffer_t buf; |
| |
| size_t total_iterated; // total bytes iterated across all calls for this iterator |
| zx_off_t offset; // current offset in the segment (relative to the segment offset) |
| // i.e. the total number of bytes iterated for the current segment |
| size_t max_length; // max length to be returned by phys_iter_next() |
| uint64_t page; // index of page in buf->phys that contains offset |
| uint64_t last_page; // last valid page index in buf->phys |
| |
| size_t next_sg_entry_idx; // next index in the scatter gather list |
| size_t segment_offset; // offset of the current scatter gather entry, relative to buffer |
| // vmo_offset, or zero if no scatter gather list is present. |
| size_t segment_length; // length of the buffer for the current scatter gather entry, |
| // or equal to buf.length if no scatter gather list is present. |
| } phys_iter_t; |
| |
| // Initializes a phys_iter_t for iterating over physical memory. |
| // max_length is the maximum length of a range returned by phys_iter_next() |
| // max_length must be either a positive multiple of PAGE_SIZE, or zero for no limit. |
| void phys_iter_init(phys_iter_t* iter, const phys_iter_buffer_t* buf, size_t max_length); |
| |
| // Returns the next physical address and length for the iterator up to size max_length. |
| // Return value is length, or zero if iteration is done. |
| size_t phys_iter_next(phys_iter_t* iter, zx_paddr_t* out_paddr); |
| |
| __END_CDECLS |
| |
| #ifdef __cplusplus |
| |
| #include <utility> |
| |
| namespace ddk { |
| |
| // Wrapper around phys_iter_t that provides C++ iterator support. |
| class PhysIter { |
| private: |
| class iterator_impl; |
| |
| public: |
| PhysIter(const phys_iter_buffer_t& buf, size_t max_length) { |
| phys_iter_init(&iter_, &buf, max_length); |
| } |
| |
| using PhysPair = std::pair<zx_paddr_t, size_t>; |
| |
| using const_iterator = iterator_impl; |
| |
| const_iterator begin() const { return const_iterator(iter_, false); } |
| const_iterator cbegin() const { return const_iterator(iter_, false); } |
| const_iterator end() const { return const_iterator(iter_, true); } |
| const_iterator cend() const { return const_iterator(iter_, true); } |
| |
| private: |
| class iterator_impl { |
| public: |
| iterator_impl(const iterator_impl& other) = default; |
| iterator_impl& operator=(const iterator_impl& other) = default; |
| |
| bool operator==(const iterator_impl& other) const { return current_ == other.current_; } |
| bool operator!=(const iterator_impl& other) const { return current_ != other.current_; } |
| |
| const PhysPair& operator*() const { return current_; } |
| |
| // Prefix |
| iterator_impl& operator++() { |
| if (current_.second == 0) { |
| return *this; |
| } |
| current_.second = phys_iter_next(&iter_, ¤t_.first); |
| return *this; |
| } |
| |
| // Postfix |
| iterator_impl operator++(int) { |
| iterator_impl ret(*this); |
| ++(*this); |
| return ret; |
| } |
| |
| private: |
| friend class PhysIter; |
| |
| iterator_impl(const phys_iter_t& iter, bool last) : iter_(iter) { |
| current_.second = phys_iter_next(&iter_, ¤t_.first); |
| while (last && current_.second != 0) { |
| current_.second = phys_iter_next(&iter_, ¤t_.first); |
| }; |
| } |
| |
| phys_iter_t iter_; |
| PhysPair current_ = {}; |
| }; |
| |
| phys_iter_t iter_; |
| }; |
| |
| } // namespace ddk |
| #endif |
| |
| #endif // SRC_LIB_DDK_INCLUDE_DDK_PHYS_ITER_H_ |