Andrew Walbran | 55ad01b | 2022-12-05 17:00:40 +0000 | [diff] [blame^] | 1 | // Copyright 2022, The Android Open Source Project |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | //! Iterators over cells, and various layers on top of them. |
| 16 | |
| 17 | use crate::{AddrCells, SizeCells}; |
| 18 | use core::{mem::size_of, ops::Range, slice::ChunksExact}; |
| 19 | |
| 20 | /// Iterator over cells of a DT property. |
| 21 | #[derive(Debug)] |
| 22 | pub struct CellIterator<'a> { |
| 23 | chunks: ChunksExact<'a, u8>, |
| 24 | } |
| 25 | |
| 26 | impl<'a> CellIterator<'a> { |
| 27 | pub(crate) fn new(bytes: &'a [u8]) -> Self { |
| 28 | const CHUNK_SIZE: usize = size_of::<<CellIterator as Iterator>::Item>(); |
| 29 | |
| 30 | Self { chunks: bytes.chunks_exact(CHUNK_SIZE) } |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | impl<'a> Iterator for CellIterator<'a> { |
| 35 | type Item = u32; |
| 36 | |
| 37 | fn next(&mut self) -> Option<Self::Item> { |
| 38 | Some(Self::Item::from_be_bytes(self.chunks.next()?.try_into().ok()?)) |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | /// Iterator over a 'reg' property of a DT node. |
| 43 | #[derive(Debug)] |
| 44 | pub struct RegIterator<'a> { |
| 45 | cells: CellIterator<'a>, |
| 46 | addr_cells: AddrCells, |
| 47 | size_cells: SizeCells, |
| 48 | } |
| 49 | |
| 50 | /// Represents a contiguous region within the address space defined by the parent bus. |
| 51 | /// Commonly means the offsets and lengths of MMIO blocks, but may have a different meaning on some |
| 52 | /// bus types. Addresses in the address space defined by the root node are CPU real addresses. |
| 53 | #[derive(Copy, Clone, Debug)] |
| 54 | pub struct Reg<T> { |
| 55 | /// Base address of the region. |
| 56 | pub addr: T, |
| 57 | /// Size of the region (optional). |
| 58 | pub size: Option<T>, |
| 59 | } |
| 60 | |
| 61 | impl<'a> RegIterator<'a> { |
| 62 | pub(crate) fn new( |
| 63 | cells: CellIterator<'a>, |
| 64 | addr_cells: AddrCells, |
| 65 | size_cells: SizeCells, |
| 66 | ) -> Self { |
| 67 | Self { cells, addr_cells, size_cells } |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | impl<'a> Iterator for RegIterator<'a> { |
| 72 | type Item = Reg<u64>; |
| 73 | |
| 74 | fn next(&mut self) -> Option<Self::Item> { |
| 75 | let make_double = |a, b| (u64::from(a) << 32) | u64::from(b); |
| 76 | |
| 77 | let addr = match self.addr_cells { |
| 78 | AddrCells::Single => self.cells.next()?.into(), |
| 79 | AddrCells::Double => make_double(self.cells.next()?, self.cells.next()?), |
| 80 | }; |
| 81 | // If the parent node specifies a value of 0 for #size-cells, 'size' shall be omitted. |
| 82 | let size = match self.size_cells { |
| 83 | SizeCells::None => None, |
| 84 | SizeCells::Single => Some(self.cells.next()?.into()), |
| 85 | SizeCells::Double => Some(make_double(self.cells.next()?, self.cells.next()?)), |
| 86 | }; |
| 87 | |
| 88 | Some(Self::Item { addr, size }) |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | /// Iterator over the address ranges defined by the /memory/ node. |
| 93 | #[derive(Debug)] |
| 94 | pub struct MemRegIterator<'a> { |
| 95 | reg: RegIterator<'a>, |
| 96 | } |
| 97 | |
| 98 | impl<'a> MemRegIterator<'a> { |
| 99 | pub(crate) fn new(reg: RegIterator<'a>) -> Self { |
| 100 | Self { reg } |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | impl<'a> Iterator for MemRegIterator<'a> { |
| 105 | type Item = Range<usize>; |
| 106 | |
| 107 | fn next(&mut self) -> Option<Self::Item> { |
| 108 | let next = self.reg.next()?; |
| 109 | let addr = usize::try_from(next.addr).ok()?; |
| 110 | let size = usize::try_from(next.size?).ok()?; |
| 111 | |
| 112 | Some(addr..addr.checked_add(size)?) |
| 113 | } |
| 114 | } |